/// <summary> /// Song of warding, protective. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongWarding( CharData ch, Spell spell, int level, Target target ) { Affect af = new Affect(); foreach( CharData victim in ch.InRoom.People ) { af.Type = Affect.AffectType.song; af.Value = spell.Name; af.Duration = level / 7; af.AddModifier(Affect.Apply.save_spell, 0 - ( ( level / 5 ) + 1 )); af.AddModifier(Affect.Apply.save_paralysis, 0 - ((level / 5) + 1)); af.AddModifier(Affect.Apply.save_petrification, 0 - ((level / 5) + 1)); af.AddModifier(Affect.Apply.save_poison, 0 - ((level / 5) + 1)); af.AddModifier(Affect.Apply.save_breath, 0 - ((level / 5) + 1)); af.SetBitvector(Affect.AFFECT_NONE); victim.AddAffect(af); } return true; }
/// <summary> /// Song of weakness. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongWeakling( CharData ch, Spell spell, int level, Target target ) { Affect af = new Affect(); foreach( CharData victim in ch.InRoom.People ) { if (victim.IsAffected( Affect.AFFECT_STRENGTH_REDUCED) || Magic.SpellSavingThrow( level, victim, AttackType.DamageType.black_magic ) ) continue; af.Type = Affect.AffectType.song; af.Value = spell.Name; af.Duration = level / 7; af.AddModifier(Affect.Apply.strength, -( level / 2 )); af.SetBitvector(Affect.AFFECT_STRENGTH_REDUCED); if( level > 25 ) { af.AddModifier( Affect.Apply.damroll, 0 - ( level / 7 )); } victim.AddAffect(af); SocketConnection.Act( "$n&n looks weaker.", victim, null, null, SocketConnection.MessageTarget.room ); victim.SendText( "You feel weaker.\r\n" ); } return true; }
/// <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> /// Song of idiocy. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongIdiocy( CharData ch, Spell spell, int level, Target target ) { Affect af = new Affect(); foreach( CharData victim in ch.InRoom.People ) { if (victim.IsAffected(Affect.AFFECT_FEEBLEMIND) || Magic.SpellSavingThrow( level, victim, AttackType.DamageType.black_magic ) ) { ch.SendText( "You failed!\r\n" ); continue; } af.Type = Affect.AffectType.song; af.Value = spell.Name; af.Duration = level / 9; af.AddModifier(Affect.Apply.intelligence, 0 - (level + 15)); af.SetBitvector(Affect.AFFECT_FEEBLEMIND); victim.AddAffect(af); SocketConnection.Act( "A dumb look crosses $n&n's face and $e starts to drool.", victim, null, null, SocketConnection.MessageTarget.room ); victim.SendText( "You feel _REALLY_ dumb.\r\n" ); } return true; }
/// <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> /// 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; }
public static void Berzerk(CharData ch, string[] str) { if( ch == null ) return; Affect af = new Affect(); /* Don't allow charmed mobs to do this, check player's level */ if ((ch.IsNPC() && ch.IsAffected( Affect.AFFECT_CHARM)) || (!ch.IsNPC() && !ch.HasSkill("berzerk"))) { ch.SendText("You're not enough of a warrior to enter a &+RBl&n&+ro&+Ro&n&+rd&+L Rage&n.\r\n"); return; } if (ch.IsAffected(Affect.AFFECT_BERZERK)) { if (MUDMath.NumberPercent() + 10 > ((PC)ch).SkillAptitude["berzerk"]) { ch.SendText("You failed to calm yourself down!\r\n"); ch.WaitState(Skill.SkillList["berzerk"].Delay); return; } ch.SendText("You no longer see targets everywhere.\r\n"); ch.RemoveAffect(Affect.AFFECT_BERZERK); ch.WaitState(Skill.SkillList["berzerk"].Delay); return; } ch.SendText("Your slam your weapon into yourself and &+Rbl&n&+ro&+Ro&n&+rd&n splatters all over!\r\n"); ch.SendText("The sight of &+Rbl&n&+ro&+Ro&n&+rd&n begins to drive you crazy!\r\n"); if (ch.CheckSkill("berzerk")) { af.Value = "berzerk"; af.Type = Affect.AffectType.skill; af.Duration = MUDMath.Dice(1, 2); af.AddModifier( Affect.Apply.hitroll, Math.Max(ch.Level / 6, 2)); af.AddModifier( Affect.Apply.damroll, Math.Max(ch.Level / 6, 2)); af.AddModifier( Affect.Apply.ac, (ch.Level / 2)); af.AddModifier( Affect.Apply.max_constitution, MUDMath.Dice(5, 9)); af.AddModifier( Affect.Apply.agility, 0 - MUDMath.Dice(5, 9)); af.AddModifier( Affect.Apply.max_strength, MUDMath.Dice(5, 9)); af.SetBitvector(Affect.AFFECT_BERZERK); ch.AddAffect(af); ch.SendText("You are overcome by &+RBl&n&+ro&+Ro&n&+rd&+L Rage&n!!\r\n"); SocketConnection.Act("$n has slipped into a &+RBl&n&+ro&+Ro&n&+rd&+L Rage&n!!", ch, null, null, SocketConnection.MessageTarget.room); return; } ch.SendText("You get a little angry, but fail to call up a &+Rblood rage&n.\r\n"); return; }
/// <summary> /// Apply poison to a weapon. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void PoisonWeapon(CharData ch, string[] str) { if (ch == null) { return; } Object obj; Object pobj = null; Affect af = new Affect(); /* Don't allow mobs or unskilled pcs to do this */ if (ch.IsNPC() || (!ch.IsNPC() && !ch.HasSkill("poison weapon"))) { ch.SendText("What do you think you are, a thief?\r\n"); return; } if (str.Length == 0) { ch.SendText("What are you trying to poison?\r\n"); return; } if (ch.Fighting != null) { ch.SendText("While you're fighting? Nice try.\r\n"); return; } if (!(obj = ch.GetObjCarrying(str[0]))) { ch.SendText("You do not have that weapon.\r\n"); return; } if (obj.ItemType != ObjTemplate.ObjectType.weapon) { ch.SendText("That item is not a weapon.\r\n"); return; } if (obj.HasFlag(ObjTemplate.ITEM_POISONED)) { ch.SendText("That weapon is already poisoned.\r\n"); return; } if (obj.Values[0] != 2) { ch.SendText("You don't have enough poison to cover that!\r\n"); return; } /* Now we have a valid weapon...check to see if we have the poison. */ foreach (Object iobj in ch.Carrying) { // here is where we should check to see if they have poison if (iobj.ItemType == ObjTemplate.ObjectType.drink_container && iobj.Values[2] == 27) { pobj = iobj; break; } } if (!pobj) { ch.SendText("You do not have any poison.\r\n"); return; } if (pobj.Values[1] <= 0 && pobj.Values[1] != -1) { SocketConnection.Act("Sorry, $p&n seems to be empty.", ch, pobj, null, SocketConnection.MessageTarget.character); return; } ch.WaitState(Skill.SkillList["poison weapon"].Delay); /* Check the skill percentage */ if (!ch.CheckSkill("poison weapon")) { ch.SendText("You failed and spill some on yourself. &+ROuch!&n\r\n"); Combat.InflictDamage(ch, ch, ch.Level, "poison weapon", ObjTemplate.WearLocation.none, AttackType.DamageType.poison); SocketConnection.Act("$n spills the &+Gpoison&n all over!", ch, null, null, SocketConnection.MessageTarget.room); pobj.Values[1] -= 2; return; } /* Can't have people smearing gunk on artifacts */ if (obj.InsultArtifact(ch)) { pobj.Values[1]--; return; } SocketConnection.Act("You apply the &+Gpoison&n to $p&n, which glistens wickedly!", ch, obj, null, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n pours the &+Gli&n&+gq&+Gu&n&+gid&n over $p&n, which glistens wickedly!", ch, obj, null, SocketConnection.MessageTarget.room); af.Value = "poison weapon"; af.Type = Affect.AffectType.skill; af.Duration = ch.Level + MUDMath.Dice(4, ch.Level / 2); af.AddModifier(Affect.Apply.none, pobj.Values[3]); af.Level = ch.Level; af.SetBitvector(Affect.AFFECT_POISON); obj.AddAffect(af); // Consume one unit of the poison source. pobj.Values[1]--; return; }
/// <summary> /// Innate command. Shows and activates innate abilitiies. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Innate(CharData ch, string[] str) { if( ch == null ) return; string text; Affect af = new Affect(); // Use innates here if (str.Length > 0 && !String.IsNullOrEmpty(str[0])) { if (!MUDString.IsPrefixOf(str[0], "strength")) { if (ch.HasInnate(Race.RACE_STRENGTH)) { if (ch.IsAffected(Affect.AFFECT_STRENGTH_INCREASED)) { ch.SendText("You are already affected by strength."); return; } if (ch.HasInnateTimer(InnateTimerData.Type.strength)) { ch.SendText("You need to rest a bit first.\r\n"); return; } af.Type = Affect.AffectType.spell; af.Value = "strength"; af.Duration = MUDMath.Dice(8, 5); af.AddModifier(Affect.Apply.strength, MUDMath.Dice(2, 4) + 15); af.SetBitvector(Affect.AFFECT_STRENGTH_INCREASED); ch.AddAffect(af); ch.SendText("You feel stronger.\r\n"); ch.AddInnateTimer(InnateTimerData.Type.strength, 24); ch.WaitState(14); } else { ch.SendText("You don't know how to do that.\r\n"); return; } } else if (!MUDString.IsPrefixOf(str[0], "levitate")) { if (ch.HasInnate(Race.RACE_LEVITATE)) { if (ch.IsAffected( Affect.AFFECT_LEVITATE)) { ch.SendText("You are already levitating."); return; } if (ch.HasInnateTimer(InnateTimerData.Type.levitate)) { ch.SendText("You need to rest a bit first.\r\n"); return; } af.Type = Affect.AffectType.spell; af.Value = "levitation"; af.Duration = MUDMath.Dice(8, 5); af.SetBitvector(Affect.AFFECT_LEVITATE); ch.AddAffect(af); ch.SendText("Your feet rise off the ground.\r\n"); ch.AddInnateTimer(InnateTimerData.Type.levitate, 24); ch.WaitState(6); } else { ch.SendText("You don't know how to do that.\r\n"); return; } } else if (!MUDString.IsPrefixOf(str[0], "faerie")) { if (ch.HasInnate(Race.RACE_FAERIE_FIRE)) { CharData victim = ch.GetCharRoom(str[0]); if (victim == null) ch.SendText("You do not see them here."); else { Spell spl = Spell.SpellList["faerie fire"]; if (spl != null) { spl.Invoke(ch, ch.Level, victim); } } } else { ch.SendText("You don't know how to do that.\r\n"); return; } } else if (!MUDString.IsPrefixOf(str[0], "invisibility")) { if (ch.HasInnate(Race.RACE_INVIS)) { if (ch.IsAffected( Affect.AFFECT_INVISIBLE)) { ch.SendText("You are already invisible!\r\n"); return; } if (ch.HasInnateTimer(InnateTimerData.Type.invisibility)) { ch.SendText("You need to rest a bit first.\r\n"); return; } af.Type = Affect.AffectType.spell; af.Value = "invisibility"; af.Duration = MUDMath.Dice(2, 8) + 4; af.SetBitvector(Affect.AFFECT_INVISIBLE); SocketConnection.Act("$n&n fades out of existence.", ch, null, null, SocketConnection.MessageTarget.room); ch.SendText("You vanish.\r\n"); ch.AddAffect(af); ch.AddInnateTimer(InnateTimerData.Type.invisibility, 24); ch.WaitState(24); } else { ch.SendText("You don't know how to do that.\r\n"); return; } } else if (!MUDString.IsPrefixOf(str[0], "enlarge")) { if (ch.HasInnate(Race.RACE_ENLARGE)) { if (ch.IsAffected(Affect.AFFECT_ENLARGED)) { ch.SendText("You are already enlarged.\r\n"); return; } if (ch.HasInnateTimer(InnateTimerData.Type.enlarge)) { ch.SendText("You need to rest a bit first.\r\n"); return; } af.Type = Affect.AffectType.spell; af.Value = "enlarge"; af.Duration = MUDMath.Dice(8, 5); af.AddModifier(Affect.Apply.size, 1); af.SetBitvector(Affect.AFFECT_NONE); ch.AddAffect(af); ch.SendText("&nYou grow to almost twice your normal size!\r\n"); SocketConnection.Act("$n&n grows to almost twice $s normal size!&n", ch, null, null, SocketConnection.MessageTarget.room); ch.AddInnateTimer(InnateTimerData.Type.enlarge, 24); ch.WaitState(10); } else { ch.SendText("You don't know how to do that.\r\n"); return; } } else if (!MUDString.IsPrefixOf(str[0], "shift")) { if (str.Length > 1 && !MUDString.IsPrefixOf(str[1], "astral")) { if (ch.HasInnate(Race.RACE_SHIFT_ASTRAL)) { if (ch.HasInnateTimer(InnateTimerData.Type.shift_astral)) { ch.SendText("You need to rest a bit first.\r\n"); return; } Spell spell = StringLookup.SpellLookup("plane shift"); if (!spell) { ch.SendText("Something seems to be blocking your ability to shift."); Log.Error("Innate Shift: 'plane shift' spell not found. Check the spells file."); return; } spell.Invoke(ch, ch.Level, new Target(str[1])); ch.AddInnateTimer(InnateTimerData.Type.shift_astral, 8); ch.WaitState(10); } else { ch.SendText("You don't know how to do that.\r\n"); return; } } else if (str.Length > 1 && !MUDString.IsPrefixOf(str[1], "prime")) { if (ch.HasInnate(Race.RACE_SHIFT_PRIME)) { if (ch.HasInnateTimer(InnateTimerData.Type.shift_prime)) { ch.SendText("You need to rest a bit first.\r\n"); return; } Spell spell = StringLookup.SpellLookup("plane shift"); if (!spell) { ch.SendText("Something seems to be blocking your ability to shift."); Log.Error("Innate Shift: 'plane shift' spell not found. Check the spells file."); return; } spell.Invoke(ch, ch.Level, new Target(str[1])); ch.AddInnateTimer(InnateTimerData.Type.shift_prime, 8); ch.WaitState(10); } else { ch.SendText("You don't know how to do that.\r\n"); return; } } } else { ch.SendText("That's not implemented yet. :(\r\n"); } return; } text = String.Format("&+BInnate abilities available to your race and class:&n\r\n"); if (ch.HasInnate(Race.RACE_BODYSLAM)) text += "&n bodyslam\r\n"; if (ch.HasInnate(Race.RACE_CHARGE)) text += "&n charge\r\n"; if (ch.HasInnate(Race.RACE_FLY)) text += "&n fly\r\n"; if (ch.HasInnate(Race.RACE_PASSDOOR)) text += "&n pass door\r\n"; if (ch.HasInnate(Race.RACE_SWIM)) text += "&n swim\r\n"; if (ch.HasInnate(Race.RACE_WATERBREATH)) text += "&n water breathing\r\n"; if (ch.HasInnate(Race.RACE_INFRAVISION)) text += "&n infravision\r\n"; if (ch.HasInnate(Race.RACE_ULTRAVISION)) text += "&n ultravision\r\n"; if (ch.HasInnate(Race.RACE_DETECT_ALIGN) || ch.IsClass(CharClass.Names.antipaladin) || ch.IsClass(CharClass.Names.paladin)) text += "&n detect align\r\n"; if (ch.HasInnate(Race.RACE_DETECT_INVIS)) text += "&n detect invis\r\n"; if (ch.HasInnate(Race.RACE_DETECT_HIDDEN)) text += "&n detect hidden\r\n"; if (ch.HasInnate(Race.RACE_MUTE)) text += "&n mute\r\n"; if (ch.HasInnate(Race.RACE_DOORBASH)) text += "&n doorbash\r\n"; if (ch.HasInnate(Race.RACE_SHRUG)) text += "&n shrug\r\n"; if (ch.HasInnate(Race.RACE_ODSNEAK)) text += "&n outdoor sneak\r\n"; if (ch.HasInnate(Race.RACE_UDSNEAK)) text += "&n underdark sneak\r\n"; if (ch.HasInnate(Race.RACE_STRENGTH)) text += "&n strength\r\n"; if (ch.HasInnate(Race.RACE_FAERIE_FIRE)) text += "&n faerie fire\r\n"; // if( ch.HasInnate( Race.RACE_STEAL )) // buf += "&n steal\r\n" ); if (ch.HasInnate(Race.RACE_ENLARGE)) text += "&n enlarge\r\n"; if (ch.HasInnate(Race.RACE_INVIS)) text += "&n invisibility\r\n"; // if( ch.HasInnate( Race.RACE_SUMMON_HOARDE )) // buf += "&n summon hoarde\r\n" ); if (ch.HasInnate(Race.RACE_SHIFT_PRIME)) text += "&n shift prime\r\n"; if (ch.HasInnate(Race.RACE_SHIFT_ASTRAL)) text += "&n shift astral\r\n"; if (ch.HasInnate(Race.RACE_LEVITATE)) text += "&n levitate\r\n"; if (ch.HasInnate(Race.RACE_BITE)) text += "&n bite\r\n"; ch.SendText(text); return; }
/* * To be used only with skills, not spells. */ static void InflictPoison( string name, int level, bool type, CharData ch, CharData victim ) { Affect af = new Affect(); if( Magic.SpellSavingThrow( level, victim, AttackType.DamageType.poison ) ) return; int typ; if (type) typ = 1; else typ = 0; af.Value = name; af.Type = Affect.AffectType.skill; af.Level = level; af.Duration = level / 4; af.AddModifier(Affect.Apply.none, typ ); af.SetBitvector( Affect.AFFECT_POISON ); victim.CombineAffect(af); if( ch != victim ) ch.SendText( "You have poisoned your victim.\r\n" ); victim.SendText( "&+GYou don't feel very well.&n\r\n" ); return; }
public static void ApplyPoison( CharData ch ) { Affect af = new Affect(); bool isSpell = false; foreach (Affect aff in ch.Affected) { if( aff.Type == Affect.AffectType.spell && aff.Value == "poison" ) { isSpell = true; } else if ((aff.Type == Affect.AffectType.skill && aff.Value == "poison weapon" || aff.Value == "poison bite") ) { foreach (AffectApplyType apply in aff.Modifiers) { if (apply.Location != Affect.Apply.none || ch.IsAffected(Affect.AFFECT_SLOW_POISON) && MUDMath.NumberBits(1) == 0) continue; Poison.Type poisonType = (Poison.Type)apply.Amount; int dam; switch (poisonType) { case Poison.Type.damage: SocketConnection.Act("$n&n goes into a brief siezure as the poison courses through $s body.", ch, null, null, SocketConnection.MessageTarget.room); ch.SendText("Your muscles twitch randomly as the poison courses through your body.\r\n"); dam = MUDMath.Dice(1, 10); if (!Magic.SpellSavingThrow(aff.Level, ch, AttackType.DamageType.poison)) InflictDamage(ch, ch, dam, "poison weapon", ObjTemplate.WearLocation.none, AttackType.DamageType.poison); else InflictDamage(ch, ch, dam / 2, "poison weapon", ObjTemplate.WearLocation.none, AttackType.DamageType.poison); return; case Poison.Type.attributes: if (!Magic.SpellSavingThrow(aff.Level, ch, AttackType.DamageType.poison)) { int lev = aff.Level; ch.AffectStrip(Affect.AffectType.skill, "poison weapon"); af.Type = Affect.AffectType.skill; af.Value = "poison"; af.Duration = lev / 4; af.Level = lev; af.AddModifier(Affect.Apply.strength, 0 - MUDMath.Dice(1, 20)); af.AddModifier(Affect.Apply.dexterity, 0 - MUDMath.Dice(1, 20)); af.AddModifier(Affect.Apply.agility, 0 - MUDMath.Dice(1, 20)); af.AddModifier(Affect.Apply.constitution, 0 - MUDMath.Dice(1, 20)); af.SetBitvector(Affect.AFFECT_POISON); ch.AddAffect(af); ch.SendText("You suddenly feel quite weak as the poison is distributed through your body.&n\r\n"); SocketConnection.Act("$n&n pales visibly and looks much weaker.", ch, null, null, SocketConnection.MessageTarget.room); return; } ch.SendText("You feel the poison working its way into your system.\r\n"); InflictDamage(ch, ch, 2, "poison weapon", ObjTemplate.WearLocation.none, AttackType.DamageType.poison); break; case Poison.Type.damage_major: dam = MUDMath.Dice(10, 10); SocketConnection.Act("$n&n screams in agony as the poison courses through $s body.", ch, null, null, SocketConnection.MessageTarget.room); ch.SendText("&+RYour blood is on fire!&n\r\n"); if (!Magic.SpellSavingThrow(aff.Level, ch, AttackType.DamageType.poison)) InflictDamage(ch, ch, dam, "poison weapon", ObjTemplate.WearLocation.none, AttackType.DamageType.poison); else InflictDamage(ch, ch, dam / 2, "poison weapon", ObjTemplate.WearLocation.none, AttackType.DamageType.poison); return; case Poison.Type.minor_para: if (!Magic.SpellSavingThrow(aff.Level, ch, AttackType.DamageType.poison)) { ch.AffectStrip(Affect.AffectType.skill, "poison_weapon"); af.Value = "poison"; af.Type = Affect.AffectType.skill; af.Duration = MUDMath.NumberRange(1, 10); af.SetBitvector(Affect.AFFECT_MINOR_PARA); ch.AddAffect(af); ch.SendText("&+YYou are paralyzed!&n\r\n"); StopFighting(ch, false); SocketConnection.Act("$n&n&+y is suddenly overcome with rigor and cannot move.&n", ch, null, null, SocketConnection.MessageTarget.room); } break; case Poison.Type.minor_para_extended: if (!Magic.SpellSavingThrow(aff.Level, ch, AttackType.DamageType.poison)) { ch.AffectStrip(Affect.AffectType.skill, "poison_weapon"); af.Value = "poison"; af.Type = Affect.AffectType.skill; af.Duration = MUDMath.NumberRange(5, 30); af.SetBitvector(Affect.AFFECT_MINOR_PARA); ch.AddAffect(af); ch.SendText("&+YYou are paralyzed!&n\r\n"); StopFighting(ch, false); SocketConnection.Act("$n&n&+y is suddenly overcome with rigor and cannot move.&n", ch, null, null, SocketConnection.MessageTarget.room); } break; case Poison.Type.major_para: if (!Magic.SpellSavingThrow(aff.Level, ch, AttackType.DamageType.poison)) { ch.AffectStrip(Affect.AffectType.skill, "poison_weapon"); af.Value = "poison"; af.Type = Affect.AffectType.skill; af.Duration = MUDMath.NumberRange(1, 10); af.SetBitvector(Affect.AFFECT_HOLD); ch.AddAffect(af); ch.SendText("&+YYou are paralyzed!&n\r\n"); StopFighting(ch, false); SocketConnection.Act("$n&n&+y is suddenly overcome with rigor and cannot move.&n", ch, null, null, SocketConnection.MessageTarget.room); } break; case Poison.Type.major_para_extended: if (!Magic.SpellSavingThrow(aff.Level, ch, AttackType.DamageType.poison)) { ch.AffectStrip(Affect.AffectType.skill, "poison_weapon"); af.Value = "poison"; af.Type = Affect.AffectType.skill; af.Duration = MUDMath.NumberRange(5, 30); af.SetBitvector(Affect.AFFECT_HOLD); ch.AddAffect(af); ch.SendText("&+YYou are paralyzed!&n\r\n"); StopFighting(ch, false); SocketConnection.Act("$n&n&+y is suddenly overcome with rigor and cannot move.&n", ch, null, null, SocketConnection.MessageTarget.room); } break; case Poison.Type.perm_constitution: // TODO: Implement perm constitution loss from poison. break; case Poison.Type.perm_hitpoints: // TODO: Implement perm hitpoint loss from poison. break; case Poison.Type.near_death: // TODO: Implement "near death" poison - one that drains HP very quickly but does not kill. break; default: Log.Error("Unimplemented or unknown poison type: " + poisonType.ToString()); break; } } } //end if } if( isSpell ) { //normal poison from the spell ch.SendText( "You shiver and suffer.\r\n" ); SocketConnection.Act( "$n&n shivers and suffers.", ch, null, null, SocketConnection.MessageTarget.room ); if (!ch.IsAffected(Affect.AFFECT_SLOW_POISON)) { InflictSpellDamage( ch, ch, 2, "poison", AttackType.DamageType.poison ); } else { // Slow poison gives them a 20% chance of avoiding damage // and does half damage when it does hit them, giving // them 40% as much damage overall as a non-slowed person if( MUDMath.NumberPercent() < 80 ) InflictSpellDamage( ch, ch, 1, "poison", AttackType.DamageType.poison ); } } else { //normal poison from a bite or weapon ch.SendText( "You shiver and suffer.\r\n" ); SocketConnection.Act( "$n&n shivers and suffers.", ch, null, null, SocketConnection.MessageTarget.room ); if (!ch.IsAffected(Affect.AFFECT_SLOW_POISON)) { InflictDamage( ch, ch, 2, "poison", ObjTemplate.WearLocation.none, AttackType.DamageType.poison ); } else { // Slow poison gives them a 20% chance of avoiding damage // and does half damage when it does hit them, giving // them 40% as much damage overall as a non-slowed person if( MUDMath.NumberPercent() < 80 ) InflictDamage( ch, ch, 1, "poison", ObjTemplate.WearLocation.none, AttackType.DamageType.poison ); } } }
/// <summary> /// Generic spell processing function. Handles basic spells based on values set in the spell file. /// </summary> /// <param name="ch"></param> /// <param name="level"></param> /// <param name="target"></param> public void GenericSpellFunction(CharData ch, int level, Target target) { switch (ValidTargets) { case TargetType.singleCharacterOffensive: { CharData opponent = (CharData)target; if (level > LevelCap) { level = LevelCap; } int damage = MUDMath.Dice( level, DamageDicePerLevel ) + BaseDamage; bool saved = Magic.SpellSavingThrow(level, opponent, DamageInflicted); bool affects = true; if (saved) { switch (SavingThrowEffect) { case SavingThrowResult.negates: damage = 0; affects = false; ch.SendText("Nothing happens.\r\n"); return; case SavingThrowResult.halfDamage: damage /= 2; affects = true; break; case SavingThrowResult.halfDamageNoAffects: damage /= 2; affects = true; break; case SavingThrowResult.fullDamageNoAffects: affects = false; break; case SavingThrowResult.none: affects = true; break; } } if (damage > 0) { Combat.InflictSpellDamage(ch, opponent, damage, this, DamageInflicted); } if (affects) { // Apply "negates" to character. for (int n = 0; n < Negates.Length; n++) { opponent.RemoveAffect(new Bitvector(n, Negates[n])); } Affect af = new Affect(); af.Level = ch.Level; af.BitVectors = Provides; af.Value = Name; af.Type = Affect.AffectType.spell; for (int p = 0; p < Provides.Length; p++) { if (Provides[p] != 0) { if (!ch.IsAffected(new Bitvector(p, Provides[p]))) { opponent.AddAffect(af); if (!String.IsNullOrEmpty(MessageCompleted)) { SocketConnection.Act(MessageCompleted, ch, null, null, SocketConnection.MessageTarget.character); } else { ch.SendText("Ok.\r\n"); } if (!String.IsNullOrEmpty(MessageCompletedToTarget)) { SocketConnection.Act(MessageCompletedToTarget, ch, opponent, null, SocketConnection.MessageTarget.victim); } if (!String.IsNullOrEmpty(MessageCompletedToRoom)) { SocketConnection.Act(this.MessageCompletedToRoom, ch, opponent, null, SocketConnection.MessageTarget.room); } } else { switch (StackingType) { case StackType.addDuration: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell addDuration stacking types are not yet supported."); case StackType.addModifier: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell addModifier stacking types are not yet supported."); case StackType.addModifierAddDuration: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell addModifierAddDuration stacking types are not yet supported."); case StackType.addModifierMaxDuration: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell addModifierMaxDuration stacking types are not yet supported."); case StackType.alwaysReplace: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell alwaysReplace stacking types are not yet supported."); case StackType.noRefresh: ch.SendText("Your spell has no effect.\r\n"); break; case StackType.replaceDuration: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell replaceDuration stacking types are not yet supported."); case StackType.takeMaxDuration: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell takeMaxDuration stacking types are not yet supported."); case StackType.takeMaxModifier: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell takeMaxModifier stacking types are not yet supported."); case StackType.takeMaxModifierAndDuration: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell takeMaxModifierAndDuration stacking types are not yet supported."); } } } } } return; } case TargetType.singleCharacterDefensive: case TargetType.self: { CharData victim; if (ValidTargets == TargetType.self) { victim = ch; } else { victim = (CharData)target; if (victim == null) { victim = ch; } } for (int n = 0; n < Negates.Length; n++) { victim.RemoveAffect(new Bitvector(n, Negates[n])); } Affect af = new Affect(); af.Level = ch.Level; af.BitVectors = Provides; af.Value = Name; af.Type = Affect.AffectType.spell; switch (this.Duration) { case SpellDurationType.oneHourPerlevel: af.Duration = level; break; case SpellDurationType.quarterHourPerLevel: af.Duration = level / 4; break; case SpellDurationType.halfHourPerLevel: af.Duration = level / 2; break; case SpellDurationType.oneDay: af.Duration = 24; break; case SpellDurationType.threeHoursPerLevel: af.Duration = level * 3; break; case SpellDurationType.twoHoursPerLevel: af.Duration = level * 2; break; case SpellDurationType.fourHoursPerLevel: af.Duration = level * 4; break; case SpellDurationType.oneHour: af.Duration = 1; break; case SpellDurationType.permanent: af.Duration = -1; break; case SpellDurationType.sixHours: af.Duration = 6; break; case SpellDurationType.threeHours: af.Duration = 3; break; case SpellDurationType.twoHours: af.Duration = 2; break; default: throw new NotSupportedException("Spells with duration type " + Duration + " are not implemented yet."); } foreach (AffectApplyType apply in Modifies) { af.AddModifier(apply.Location, apply.Amount); } for( int p = 0; p < Provides.Length; p++ ) { if( Provides[p] != 0 ) { if (!ch.IsAffected(new Bitvector(p, Provides[p]))) { victim.AddAffect(af); if (!String.IsNullOrEmpty(MessageCompleted)) { SocketConnection.Act(MessageCompleted, ch, null, null, SocketConnection.MessageTarget.character); } else { ch.SendText("Ok.\r\n"); } if (!String.IsNullOrEmpty(MessageCompletedToTarget)) { SocketConnection.Act(MessageCompletedToTarget, ch, victim, null, SocketConnection.MessageTarget.victim); } if (!String.IsNullOrEmpty(MessageCompletedToRoom)) { SocketConnection.Act(MessageCompletedToRoom, ch, victim, null, SocketConnection.MessageTarget.room); } } else { switch (StackingType) { case StackType.addDuration: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell addDuration stacking types are not yet supported."); case StackType.addModifier: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell addModifier stacking types are not yet supported."); case StackType.addModifierAddDuration: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell addModifierAddDuration stacking types are not yet supported."); case StackType.addModifierMaxDuration: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell addModifierMaxDuration stacking types are not yet supported."); case StackType.alwaysReplace: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell alwaysReplace stacking types are not yet supported."); case StackType.noRefresh: ch.SendText("Your spell has no effect.\r\n"); break; case StackType.replaceDuration: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell replaceDuration stacking types are not yet supported."); case StackType.takeMaxDuration: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell takeMaxDuration stacking types are not yet supported."); case StackType.takeMaxModifier: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell takeMaxModifier stacking types are not yet supported."); case StackType.takeMaxModifierAndDuration: ch.SendText("Your spell has no effect.\r\n"); throw new NotSupportedException("Spell takeMaxModifierAndDuration stacking types are not yet supported."); } } } } } break; case TargetType.multipleCharacterOffensive: { } break; case TargetType.objectCorpse: { } break; case TargetType.objectInInventory: { } break; case TargetType.objectInRoom: { } break; case TargetType.objectOrCharacter: { } break; case TargetType.ritual: { } break; case TargetType.singleCharacterRanged: { CharData opponent = (CharData)target; if (level > LevelCap) level = LevelCap; int damage = MUDMath.Dice(level, DamageDicePerLevel) + BaseDamage; bool saved = Magic.SpellSavingThrow(level, opponent, DamageInflicted); bool affects = true; if (saved) { switch (SavingThrowEffect) { case SavingThrowResult.negates: damage = 0; affects = false; break; case SavingThrowResult.halfDamage: damage /= 2; affects = true; break; case SavingThrowResult.halfDamageNoAffects: damage /= 2; affects = false; break; case SavingThrowResult.fullDamageNoAffects: affects = false; break; case SavingThrowResult.none: affects = true; break; } } if (damage > 0) { Combat.InflictSpellDamage(ch, opponent, damage, this, DamageInflicted); } if (affects) { // TODO: Apply "provides" to character. // TODO: Apply "negates" to character. } return; } case TargetType.singleCharacterWorld: { } break; case TargetType.trap: { } break; case TargetType.none: { Log.Error("Magic spell '" + Name + "' is flagged as TargetType.none. This should never happen. Fix it."); } break; } }
/// <summary> /// Updates all characters, mobs and players alike. /// /// This function is performance sensitive. /// </summary> static void CharacterUpdate() { CharData ch; CharData chSave = null; CharData chQuit = null; _hunger = ( ( ++_hunger ) % 16 ); DateTime saveTime = Database.SystemData.CurrentTime; for( int i = (Database.CharList.Count - 1); i >= 0; i-- ) { ch = Database.CharList[i]; if( !ch.InRoom ) { continue; } if( ch.CurrentPosition == Position.stunned ) ch.UpdatePosition(); if( ch.CurrentPosition == Position.dead ) { ch.SendText( "&+lYour soul finally leaves your body.&n\r\n" ); SocketConnection.Act( "&+l$n&+l's corpse grows &+bcold&+l.", ch, null, null, SocketConnection.MessageTarget.room ); Combat.KillingBlow( ch, ch ); continue; } if( ch.CurrentPosition == Position.fighting && !ch.Fighting ) ch.CurrentPosition = Position.standing; if( !ch.IsNPC() ) ch.UpdateInnateTimers(); Affect affect; for( int j = (ch.Affected.Count - 1); j >= 0; j-- ) { affect = ch.Affected[j]; if( affect.Duration > 0 ) affect.Duration--; else if( affect.Duration < 0 ) { // Permanent affect, not on a timer. } else { if( affect.Type == Affect.AffectType.skill && Skill.SkillList[ affect.Value ].WearOffMessage.Length > 0 ) { ch.SendText(Skill.SkillList[affect.Value].WearOffMessage); ch.SendText( "\r\n" ); if( affect.Value == "vampiric bite" ) ch.SetPermRace( Race.RACE_VAMPIRE ); } else if (affect.Type == Affect.AffectType.spell && Spell.SpellList[affect.Value].MessageWearOff.Length > 0) { ch.SendText( Spell.SpellList[ affect.Value ].MessageWearOff ); ch.SendText( "\r\n" ); } else if( affect.Type == Affect.AffectType.song && Database.SongList[ affect.Value ].MessageWearOff.Length > 0 ) { ch.SendText( Database.SongList[ affect.Value ].MessageWearOff ); ch.SendText( "\r\n" ); } ch.RemoveAffect( ch.Affected[j] ); } } if( ch.IsAffected( Affect.AFFECT_VACANCY ) && !ch.IsAffected( Affect.AFFECT_HIDE ) ) { ch.SendText( "You become part of your surroundings.\r\n" ); SocketConnection.Act( "$n&n fades from view.", ch, null, null, SocketConnection.MessageTarget.room ); ch.SetAffectBit( Affect.AFFECT_HIDE ); } // Careful with the damages here, MUST NOT refer to ch after damage taken, // as it may be lethal damage (on NPC). if (ch.IsAffected(Affect.AFFECT_DISEASE)) { Affect plague = new Affect(); int level = 0; SocketConnection.Act( "$n&n writhes in agony as plague sores erupt from $s skin.", ch, null, null, SocketConnection.MessageTarget.room ); ch.SendText( "You writhe in agony from the plague.\r\n" ); foreach (Affect af in ch.Affected) { if (af.Type == Affect.AffectType.spell && af.Value == "plague") { level = af.Level; break; } } if( level == 0 ) { ch.RemoveAffect( Affect.AFFECT_DISEASE ); continue; } if( level == 1 ) continue; plague.Type = Affect.AffectType.spell; plague.Value = "plague"; plague.Level = level - 1; plague.Duration = MUDMath.NumberRange( 1, 2 * plague.Level ); plague.AddModifier(Affect.Apply.strength, -5); plague.SetBitvector( Affect.AFFECT_DISEASE ); int save = plague.Level; foreach( CharData ivch in ch.InRoom.People ) { if( save != 0 && !Magic.SpellSavingThrow( save, ivch, AttackType.DamageType.disease ) && !ivch.IsImmortal() && !ivch.IsAffected(Affect.AFFECT_DISEASE) && MUDMath.NumberBits( 4 ) == 0 ) { ivch.SendText( "You feel hot and feverish.\r\n" ); SocketConnection.Act( "$n&n shivers and looks very ill.", ivch, null, null, SocketConnection.MessageTarget.room ); ivch.CombineAffect(plague); } } int dam = Math.Min( ch.Level, 5 ); ch.CurrentMana -= dam; ch.CurrentMoves -= dam; Combat.InflictSpellDamage( ch, ch, dam, "plague", AttackType.DamageType.disease ); } if( ( Database.SystemData.GameHour > 5 && Database.SystemData.GameHour < 21 ) && CharData.CheckSusceptible( ch, Race.DamageType.light ) ) { int dmg = 0; // Shouldn't this mess be a switch statement? if( ch.IsUnderground() ) { dmg = 0; } if( ch.InRoom.TerrainType == TerrainType.inside ) { dmg = 1; } else { if( ch.InRoom.TerrainType == TerrainType.forest || ch.InRoom.TerrainType == TerrainType.swamp ) { dmg = 2; } else { dmg = 4; } } if( Database.SystemData.WeatherData.Sky == Sysdata.SkyType.cloudy ) dmg /= 2; if (Database.SystemData.WeatherData.Sky == Sysdata.SkyType.rain) { dmg *= 3; dmg /= 4; } ch.SendText( "&+RThe heat of the sun feels terrible!&n\r\n" ); Combat.InflictSpellDamage( ch, ch, dmg, Spell.SpellList["poison"], AttackType.DamageType.light ); } if( ch.InRoom.TerrainType == TerrainType.underwater_has_ground && ( !ch.IsImmortal() && !ch.IsAffected( Affect.AFFECT_BREATHE_UNDERWATER ) && !CharData.CheckImmune( ch, Race.DamageType.drowning ) && !ch.HasInnate( Race.RACE_WATERBREATH ) ) ) { ch.SendText( "You can't breathe!\r\n" ); SocketConnection.Act( "$n&n sputters and chokes!", ch, null, null, SocketConnection.MessageTarget.room ); ch.Hitpoints -= 5; ch.UpdatePosition(); } else if( ch.InRoom.TerrainType != TerrainType.underwater_has_ground && ch.InRoom.TerrainType != TerrainType.unswimmable_water && ch.InRoom.TerrainType != TerrainType.swimmable_water && ch.HasInnate( Race.RACE_WATERBREATH ) && !Race.RaceList[ch.GetRace()].Name.Equals("Object", StringComparison.CurrentCultureIgnoreCase) && ch.GetRace() != Race.RACE_GOD ) { ch.SendText( "You can't breathe!\r\n" ); SocketConnection.Act( "$n&n sputters and gurgles!", ch, null, null, SocketConnection.MessageTarget.room ); ch.Hitpoints -= 5; ch.UpdatePosition(); } else if( ch.IsAffected( Affect.AFFECT_POISON ) ) { Combat.ApplyPoison(ch); } else { string text; if( ch.CurrentPosition == Position.incapacitated ) { text = String.Format( "char_update: {0}&n is incapacitated.", ch.Name ); ImmortalChat.SendImmortalChat( null, ImmortalChat.IMMTALK_SPAM, 0, text ); if( ch.HasInnate( Race.RACE_REGENERATE ) && ch.Hitpoints < ch.GetMaxHit() ) { ++ch.Hitpoints; } else if( !ch.IsNPC() ) { Combat.InflictDamage(ch, ch, 1, String.Empty, ObjTemplate.WearLocation.none, AttackType.DamageType.none); } else if( MUDMath.NumberPercent() < 50 ) { ch.Hitpoints--; } } else if( ch.CurrentPosition == Position.mortally_wounded ) { text = String.Format( "char_update: {0}&n is mortally wounded.", ch.Name ); ImmortalChat.SendImmortalChat( null, ImmortalChat.IMMTALK_SPAM, 0, text ); if( ch.HasInnate( Race.RACE_REGENERATE ) && ch.Hitpoints < ch.GetMaxHit() ) { ++ch.Hitpoints; } else if( !ch.IsNPC() ) { Combat.InflictDamage(ch, ch, 2, String.Empty, ObjTemplate.WearLocation.none, AttackType.DamageType.none); } else { Combat.InflictDamage(ch, ch, 1, String.Empty, ObjTemplate.WearLocation.none, AttackType.DamageType.none); } } } ch.UpdatePosition(); // Refresh stoneskin on perm stone mobs. if( ch.IsNPC() && Macros.IsSet( ch.MobileTemplate.AffectedBy[ Affect.AFFECT_STONESKIN.Group ], Affect.AFFECT_STONESKIN.Vector ) && !ch.IsAffected( Affect.AFFECT_STONESKIN ) ) { ch.SetAffectBit( Affect.AFFECT_STONESKIN ); SocketConnection.Act( "$n&+L's skin turns to stone.&n", ch, null, null, SocketConnection.MessageTarget.room ); } // Thats all for mobs. if( ch.IsNPC() ) { continue; } if( ch.CurrentPosition == Position.dead ) { Combat.KillingBlow( ch, ch ); continue; } // Find player with oldest save time. if( ( !ch.Socket || ch.Socket.ConnectionStatus == SocketConnection.ConnectionState.playing ) && ch.Level >= 2 && ch.SaveTime < saveTime ) { chSave = ch; saveTime = ch.SaveTime; } if( ( ch.Level < Limits.LEVEL_AVATAR || ( !ch.Socket && !ch.IsSwitched ) ) ) { Object obj = Object.GetEquipmentOnCharacter( ch, ObjTemplate.WearLocation.hand_one ); if( ( obj ) && obj.ItemType == ObjTemplate.ObjectType.light && obj.Values[ 2 ] > 0 ) { if( --obj.Values[ 2 ] == 0 && ch.InRoom ) { --ch.InRoom.Light; SocketConnection.Act( "$p&n goes out.", ch, obj, null, SocketConnection.MessageTarget.room ); SocketConnection.Act( "$p&n goes out.", ch, obj, null, SocketConnection.MessageTarget.character ); obj.RemoveFromWorld(); } } if( ch.Timer > 15 && !ch.IsSwitched ) chQuit = ch; // This is so that hunger updates once every 16 CharacterUpdates, // This is so that thirst updates once every 16 CharacterUpdates, // This is so that drunkeness updates once every 2 CharacterUpdates, all at different intervals. if( ( _hunger % 2 ) == 1 ) { ch.AdjustDrunk( -1 ); } if( _hunger == 4 ) { ch.AdjustHunger(-1); } if( _hunger == 8 ) { ch.AdjustThirst(-1); } if (ch.IsAffected(Affect.AFFECT_THIRST)) { ch.AdjustThirst(-2); } if( ( ch.Hitpoints - ch.GetMaxHit() ) > 50 && ( _hunger % 5 == 0 ) ) { ch.Hitpoints--; } else if( ( ch.Hitpoints - ch.GetMaxHit() ) > 100 && ( _hunger % 4 == 0 ) ) { ch.Hitpoints--; } else if( ( ch.Hitpoints - ch.GetMaxHit() ) > 150 ) { ch.Hitpoints--; } } } // Autosave and autoquit. Check that these chars still exist. if( chSave || chQuit ) { foreach( CharData it in Database.CharList ) { ch = it; if( ch == chSave ) { CharData.SavePlayer( ch ); } if( ch == chQuit ) { CommandType.Interpret(ch, "camp"); } } } return; }