static bool SpecInferno(System.Object obj, System.Object owner, bool hit) { CharData keeper = (CharData)owner; /* check to make sure the object has an owner and he's in the room */ if (!keeper || !keeper.InRoom) { return(false); } if (MUDMath.NumberPercent() < 10) { SocketConnection.Act("&+LA faint hum can be heard from&n $p&n &+Lcarried by&n $n&n.", keeper, (Object)obj, null, SocketConnection.MessageTarget.room); SocketConnection.Act("&+LA faint hum can be heard from&n $p&n &+Lyou are carrying.&n", keeper, (Object)obj, null, SocketConnection.MessageTarget.character); return(true); } /* check to see if the weapon is in combat */ if (!keeper.Fighting || !hit) { return(false); } if (keeper.Fighting && keeper.InRoom && MUDMath.NumberPercent() < 10 && keeper.Fighting.Hitpoints >= -9) { SocketConnection.Act("&+r$n&+r's $p&+r glows brightly and emits a storm of fire!&n", keeper, (Object)obj, null, SocketConnection.MessageTarget.room); SocketConnection.Act("Your $p&+r glows brightly and emits a storm of fire!&n", keeper, (Object)obj, null, SocketConnection.MessageTarget.character); int dam = MUDMath.Dice(10, 10) + 150; foreach (CharData victim in keeper.InRoom.People) { if (victim.IsSameGroup(keeper) || victim == keeper || victim.Hitpoints < -9) { continue; } if (victim.FlightLevel != keeper.FlightLevel) { continue; } if (Magic.SpellSavingThrow(((Object)obj).Level, victim, AttackType.DamageType.fire)) { Combat.InflictSpellDamage(keeper, victim, dam / 2, "inferno", AttackType.DamageType.fire); } else { Combat.InflictSpellDamage(keeper, victim, dam, "inferno", AttackType.DamageType.fire); } } } return(false); }
/// <summary> /// Sets the level of an undead creature based on info from the character, /// the corpse, and the type of undead being raised. /// </summary> /// <param name="ch"></param> /// <param name="corpseLevel"></param> /// <param name="petType"></param> /// <returns></returns> public static int FuzzyLevel(CharData ch, int corpseLevel, int petType) { int temp = corpseLevel; if ((corpseLevel > Table[petType].MaxLevel) && (corpseLevel <= ch.Level)) { return(Table[petType].MaxLevel); } if ((corpseLevel >= ch.Level) && (ch.Level <= Table[petType].MaxLevel)) { temp = (ch.Level + ((MUDMath.Dice(1, ((corpseLevel + 1) - ch.Level))) - 1)); return(Math.Min(temp, Table[petType].MaxLevel)); } if (ch.Level >= corpseLevel) { return(Math.Min(ch.Level, Table[petType].MaxLevel)); } return(temp); }
/// <summary> /// Song of quagmire (move drain). /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongQuagmire(CharData ch, Spell spell, int level, Target target) { foreach (CharData victim in ch.InRoom.People) { if (victim.CurrentMoves < 0) { continue; } victim.CurrentMoves -= MUDMath.Dice(2, (level / 2)) + 5; if (victim.CurrentMoves < 0) { victim.CurrentMoves = 0; } victim.SendText("Your feet feel mired to the ground.\r\n"); } return(true); }
/// <summary> /// Song of healing. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongHealing(CharData ch, Spell spell, int level, Target target) { foreach (CharData victim in ch.InRoom.People) { if (!ch.IsSameGroup(victim)) { continue; } int heal = MUDMath.Dice(4, (level / 3)) + 1; if (victim.Hitpoints < victim.GetMaxHit()) { victim.Hitpoints = Math.Min(victim.Hitpoints + heal, victim.GetMaxHit()); } victim.UpdatePosition(); victim.SendText("&+WYour wounds begin to heal.&n\r\n"); } return(true); }
/// <summary> /// Initialize a new PC with default values. /// </summary> public PC() { ++NumPc; Prompt = "&+g<%hhp %mm %vmv>\r\n<&n%D %B&+g>&n "; Score = 0.0; PageLength = 25; IsSwitched = false; Speaking = 0; ActionFlags[0] = PLAYER_CAST_TICK.Vector | PLAYER_TELL.Vector | PLAYER_SHOUT.Vector | PLAYER_PROMPT.Vector | PLAYER_COMBINE.Vector | PLAYER_MAP.Vector | PLAYER_PAGER.Vector | PLAYER_AUTOWRAP.Vector | PLAYER_COLOR.Vector | PLAYER_VICIOUS.Vector; HitpointModifier = 0; GuildRank = 0; Train = 0; Frags = 0; PlayerKills = 0; PlayerDeaths = 0; MobKills = 0; MobDeaths = 0; FirstaidTimer = 0; CreationTime = new DateTime(); // Creation time, actual. Created = new ItemStatus(); Destroyed = new ItemStatus(); Birthdate = new DateTime(); // Creation time used for age calculations. Unlike creation time, it can change. OriginalHome = StaticRooms.GetRoomNumber("ROOM_NUMBER_START"); CurrentHome = StaticRooms.GetRoomNumber("ROOM_NUMBER_START"); Height = 60 + MUDMath.Dice(2, 10); Weight = 15 + (Height * 2); RaceStrMod = 0; RaceIntMod = 0; RaceWisMod = 0; RaceDexMod = 0; RaceConMod = 0; RaceAgiMod = 0; RaceChaMod = 0; RacePowMod = 0; RaceLukMod = 0; MaxStrMod = 0; MaxIntMod = 0; MaxWisMod = 0; MaxDexMod = 0; MaxConMod = 0; MaxAgiMod = 0; MaxChaMod = 0; MaxPowMod = 0; MaxLukMod = 0; AggressiveLevel = -1; Tradition = 0; SkillPoints = 0; Chi = 0; MaxChi = 0; Stance = String.Empty; LastRentLocation = 0; LostHp = 0; MonkRestriction = 0; IsWieldingTwohanded = false; Editing = SocketConnection.EditState.none; Security = 0; int count; SpellAptitude = new SerializableDictionary <String, Int32>(); SkillAptitude = new SerializableDictionary <String, Int32>(); SongAptitude = new SerializableDictionary <String, Int32>(); MonkAptitude = new SerializableDictionary <String, Int32>(); LanguageAptitude = new int[Race.MAX_LANG]; for (count = 0; count < Race.MAX_LANG; ++count) { LanguageAptitude[count] = 0; } TrophyData = new TrophyData[Limits.MAX_LEVEL]; for (count = 0; count < Limits.MAX_LEVEL; ++count) { TrophyData[count] = new TrophyData(); TrophyData[count].MobIndexNumber = 0; TrophyData[count].NumberKilled = 0; } Thirst = 48; Hunger = 48; Drunk = 0; Bank = new Coins(); Bank.Copper = 0; Bank.Silver = 0; Bank.Gold = 0; Bank.Platinum = 0; }
/// <summary> /// Create an instance of a mobile from the provided template. /// </summary> /// <param name="mobTemplate"></param> /// <returns></returns> public static CharData CreateMobile(MobTemplate mobTemplate) { int count; if (!mobTemplate) { Log.Error("CreateMobile: null MobTemplate.", 0); throw new NullReferenceException(); } CharData mob = new CharData(); mob.MobileTemplate = mobTemplate; mob.Followers = null; mob.Name = mobTemplate.PlayerName; mob.ShortDescription = mobTemplate.ShortDescription; mob.FullDescription = mobTemplate.FullDescription; mob.Description = mobTemplate.Description; mob.SpecialFunction = mobTemplate.SpecFun; mob.SpecialFunctionNames = mobTemplate.SpecFunNames; mob.CharacterClass = mobTemplate.CharacterClass; mob.Level = MUDMath.FuzzyNumber(mobTemplate.Level); mob.ActionFlags = mobTemplate.ActionFlags; mob.CurrentPosition = mobTemplate.DefaultPosition; mob.ChatterBotName = mobTemplate.ChatterBotName; // TODO: Look up the chatter bot name and load a runtime bot into the variable. mob.ChatBot = null; for (count = 0; count < Limits.NUM_AFFECT_VECTORS; ++count) { mob.AffectedBy[count] = mobTemplate.AffectedBy[count]; } mob.Alignment = mobTemplate.Alignment; mob.Gender = mobTemplate.Gender; mob.SetPermRace(mobTemplate.Race); mob.CurrentSize = Race.RaceList[mob.GetRace()].DefaultSize; if (mob.HasActionBit(MobTemplate.ACT_SIZEMINUS)) { mob.CurrentSize--; } if (mob.HasActionBit(MobTemplate.ACT_SIZEPLUS)) { mob.CurrentSize++; } mob.CastingSpell = 0; mob.CastingTime = 0; mob.PermStrength = MUDMath.Dice(2, 46) + 8; mob.PermIntelligence = MUDMath.Dice(2, 46) + 8; mob.PermWisdom = MUDMath.Dice(2, 46) + 8; mob.PermDexterity = MUDMath.Dice(2, 46) + 8; mob.PermConstitution = MUDMath.Dice(2, 46) + 7; mob.PermAgility = MUDMath.Dice(2, 46) + 8; mob.PermCharisma = MUDMath.Dice(2, 46) + 8; mob.PermPower = MUDMath.Dice(2, 46) + 8; mob.PermLuck = MUDMath.Dice(2, 46) + 8; mob.ModifiedStrength = 0; mob.ModifiedIntelligence = 0; mob.ModifiedWisdom = 0; mob.ModifiedDexterity = 0; mob.ModifiedConstitution = 0; mob.ModifiedAgility = 0; mob.ModifiedCharisma = 0; mob.ModifiedPower = 0; mob.ModifiedLuck = 0; mob.Resistant = mobTemplate.Resistant; mob.Immune = mobTemplate.Immune; mob.Susceptible = mobTemplate.Susceptible; mob.Vulnerable = mobTemplate.Vulnerable; mob.MaxMana = mob.Level * 10; if (Race.RaceList[mobTemplate.Race].Coins) { int level = mobTemplate.Level; mob.ReceiveCopper(MUDMath.Dice(12, level) / 32); mob.ReceiveSilver(MUDMath.Dice(9, level) / 32); mob.ReceiveGold(MUDMath.Dice(5, level) / 32); mob.ReceivePlatinum(MUDMath.Dice(2, level) / 32); } else { mob.SetCoins(0, 0, 0, 0); } mob.ArmorPoints = MUDMath.Interpolate(mob.Level, 100, -100); // * MOB HITPOINTS * // // Was level d 8, upped it to level d 13 // considering mobs *still* won't have as many hitpoints as some players until // at least level 10, this shouldn't be too big an upgrade. // // Mob hitpoints are not based on constitution *unless* they have a // constitution modifier from an item, spell, or other affect // In light of recent player dissatisfaction with the // mob hitpoints, I'm implementing a log curve, using // hp = exp( 2.15135 + level*0.151231) // This will will result in the following hp matrix: // Level Hitpoints // 20 175 // 30 803 // 40 3643 // 50 16528 // 55 35207 // 60 75000 mob.MaxHitpoints = MUDMath.Dice(mob.Level, 13) + 1; // Mob hps are non-linear above level 10. if (mob.Level > 20) { int upper = (int)Math.Exp(1.85 + mob.Level * 0.151231); int lower = (int)Math.Exp(1.80 + mob.Level * 0.151231); mob.MaxHitpoints += MUDMath.NumberRange(lower, upper); } else if (mob.Level > 10) { mob.MaxHitpoints += MUDMath.NumberRange(mob.Level * 2, ((mob.Level - 8) ^ 2 * mob.Level) / 2); } // Demons/devils/dragons gain an extra 30 hitpoints per level (+1500 at lvl 50). if (mob.GetRace() == Race.RACE_DEMON || mob.GetRace() == Race.RACE_DEVIL || mob.GetRace() == Race.RACE_DRAGON) { mob.MaxHitpoints += (mob.Level * 30); } mob.Hitpoints = mob.GetMaxHit(); // Horses get more moves, necessary for mounts. if (Race.RaceList[mob.GetRace()].Name.Equals("Horse", StringComparison.CurrentCultureIgnoreCase)) { mob.MaxMoves = 290 + MUDMath.Dice(4, 5); mob.CurrentMoves = mob.MaxMoves; } mob.LoadRoomIndexNumber = 0; // Insert in list. CharList.Add(mob); // Increment count of in-game instances of mob. mobTemplate.NumActive++; return(mob); }
static bool SpecHammer(System.Object obj, System.Object owner, bool hit) { CharData keeper = (CharData)owner; bool retval = false; if (!keeper) { return(false); } //Hum if ((!keeper.Fighting && MUDMath.NumberPercent() < 10) || (keeper.Fighting && MUDMath.NumberPercent() < 2)) { SocketConnection.Act("&+LA faint hum can be heard from&n $p&n &+Lcarried by&n $n&n.", keeper, (Object)obj, null, SocketConnection.MessageTarget.room); SocketConnection.Act("&+LA faint hum can be heard from&n $p&n &+Lyou are carrying.&n", keeper, (Object)obj, null, SocketConnection.MessageTarget.character); if (!keeper.IsAffected(Affect.AFFECT_STONESKIN) && MUDMath.NumberPercent() < 30) { Spell spl = Spell.SpellList["stoneskin"]; if (spl != null) { spl.Invoke(keeper, 60, keeper); } } retval = true; } if (!keeper.Fighting) { return(retval); } // it fires off 1 in 12 times if (MUDMath.NumberPercent() > 8) { return(false); } // if not wielded as primary, do nothing if (Object.GetEquipmentOnCharacter(keeper, ObjTemplate.WearLocation.hand_one) != obj) { return(false); } // grumbar's hammer needs to be grounded to work if (keeper.FlightLevel != 0) { return(false); } // need to have some earthly elements around // if ( keeper.in_room.sector == RoomIndex.TerrainType.plane_of_air || // keeper.in_room.sector == RoomIndex.TerrainType.plane_of_water || // keeper.in_room.sector == RoomIndex.TerrainType.plane_of_fire ) // return false; CharData vict = keeper.Fighting; switch (MUDMath.NumberRange(1, 3)) { case 1: //throw a wall int dir = MUDMath.NumberRange(0, Limits.MAX_DIRECTION - 1); if (keeper.InRoom.ExitData[dir]) { Spell spl = Spell.SpellList["wall of stone"]; if (spl != null) { spl.Invoke(keeper, 50, dir.ToString()); } } retval = true; break; case 2: // earthen rain if (!keeper.IsOutside()) { retval = false; break; } SocketConnection.Act("Your $p crushes $N in a rain of &+yearth&N and &+Lstone&N!", keeper, (Object)obj, vict, SocketConnection.MessageTarget.character); SocketConnection.Act("$n's $p crushes you under a rain of &+yearth&N and &+Lstone&N!", keeper, (Object)obj, vict, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n's $p crushes $N under a rain of &+yearth&N and &+Lstone&N!.", keeper, (Object)obj, vict, SocketConnection.MessageTarget.everyone_but_victim); // same damage as earthen rain at level 50 int dam = MUDMath.Dice(150, 3) + 100; Combat.InflictSpellDamage(keeper, vict, dam, "earthen rain", AttackType.DamageType.crushing); retval = true; break; case 3: // cause an earthquake SocketConnection.Act("Your $p causes the ground to rise up!", keeper, (Object)obj, vict, SocketConnection.MessageTarget.character); SocketConnection.Act("$n's $p blasts the ground with a &+yshockwave&N!", keeper, (Object)obj, null, SocketConnection.MessageTarget.room); foreach (CharData targetChar in keeper.InRoom.People) { if ((targetChar == keeper) || targetChar.IsImmortal()) { continue; } if (keeper.IsSameGroup(targetChar)) { continue; } if (targetChar.IsAffected(Affect.AFFECT_FLYING)) { continue; } if (keeper.IsNPC() && targetChar.IsNPC() && !vict.IsSameGroup(targetChar)) { continue; } if (Magic.SpellSavingThrow(60, targetChar, AttackType.DamageType.earth)) { SocketConnection.Act("You wobble precipitously, but keep your feet.", keeper, null, targetChar, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n stumbles slightly but keeps $s balance.", targetChar, null, null, SocketConnection.MessageTarget.room); } else { SocketConnection.Act("You are knocked to the ground!", keeper, null, targetChar, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n is knocked to the ground!", targetChar, null, null, SocketConnection.MessageTarget.room); targetChar.CurrentPosition = Position.kneeling; targetChar.WaitState(Event.TICK_COMBAT); } } // end for retval = true; break; default: break; } //end switch return(retval); }
/// <summary> /// Updates the weather and game hour. Also updates things that depend on the game hour. /// /// Weather depends on the time of year. /// </summary> public void UpdateWeather() { string text = String.Empty; UpdatePlayerCount(); switch (++GameHour) { case 4: WeatherData.Sunlight = SunType.moonset; if (WeatherData.MoonPhase != MoonPhase.new_moon) { text = "&+cThe &+Cmoon&n&+c slowly &+Lvanishes&n&+c from the horizon.&n\r\n"; } break; case 6: WeatherData.Sunlight = SunType.sunrise; text = "&+cThe first &+Clights&n&+c of &+md&+Maw&n&+mn &n&+cilluminate the&+C sky&n.\r\n"; WeatherData.Temperature += MUDMath.FuzzyNumber(10); break; case 7: WeatherData.Sunlight = SunType.daytime; text = "&+MA new day has begun as the &+Ysun&+M rises&n.&n\r\n"; if (GameMonth <= 4 || GameMonth >= 15) { WeatherData.Temperature = MUDMath.FuzzyNumber(20); } else { WeatherData.Temperature = MUDMath.FuzzyNumber(50); } break; case 12: text = "&+cThe &+Ysun&n &+cnow hangs at high noon&n.\r\n"; WeatherData.Temperature += MUDMath.FuzzyNumber(20); break; case 19: WeatherData.Sunlight = SunType.sunset; text = "&+mThe &+Ysun&n&+m slowly slips off the &+Mhorizon&n.\r\n"; WeatherData.Temperature -= MUDMath.FuzzyNumber(20); break; case 20: WeatherData.Sunlight = SunType.night; text = "&+LThe night begins as darkness settles across the lands&n.\r\n"; WeatherData.Temperature -= MUDMath.FuzzyNumber(10); break; case Limits.HOURS_PER_DAY: WeatherData.Sunlight = SunType.moonrise; WeatherData.Temperature -= MUDMath.FuzzyNumber(10); GameHour = 0; GameDay++; // Moon stuff WeatherData.Moonday++; if (WeatherData.Moonday >= LUNAR_CYCLE_DAYS) { WeatherData.MoonPhase = MoonPhase.new_moon; WeatherData.Moonday = 0; } else { if (WeatherData.Moonday < (LUNAR_CYCLE_DAYS / 8)) { WeatherData.MoonPhase = MoonPhase.new_moon; } else if (WeatherData.Moonday < (LUNAR_CYCLE_DAYS / 4)) { WeatherData.MoonPhase = MoonPhase.quarter; } else if (WeatherData.Moonday < (LUNAR_CYCLE_DAYS * 3 / 8)) { WeatherData.MoonPhase = MoonPhase.half; } else if (WeatherData.Moonday < (LUNAR_CYCLE_DAYS / 2)) { WeatherData.MoonPhase = MoonPhase.three_quarter; } else if (WeatherData.Moonday < (LUNAR_CYCLE_DAYS * 5 / 8)) { WeatherData.MoonPhase = MoonPhase.full; } else if (WeatherData.Moonday < (LUNAR_CYCLE_DAYS * 3 / 4)) { WeatherData.MoonPhase = MoonPhase.three_quarter; } else if (WeatherData.Moonday < (LUNAR_CYCLE_DAYS * 7 / 8)) { WeatherData.MoonPhase = MoonPhase.half; } else if (WeatherData.Moonday < (LUNAR_CYCLE_DAYS)) { WeatherData.MoonPhase = MoonPhase.quarter; } } switch (WeatherData.MoonPhase) { default: break; case MoonPhase.new_moon: text += "&+LThe night sky is overshadowed by an uncommon darkness.&n\r\n"; break; case MoonPhase.full: text += "&n&+LThe &+Cmoon&n&+L rises full, casting a &n&+wsi&+Wlv&n&+wer &n&+cglow&+L across the entire sky.&n\r\n"; break; case MoonPhase.three_quarter: text += "&n&+LThe &+Cmoon&n&+L ascends, a small &n&+csliver&+L absent against the night sky.&n\r\n"; break; case MoonPhase.half: text += "&n&+LA giant half-circle, the &+Cmoon&n&+L rises against the blanket of night.&n\r\n"; break; case MoonPhase.quarter: text += "&n&+LThe &+Cmoon&n&+L rises, a &n&+wsi&+Wlv&n&+wer &+csliver&n&+L against the dark firmament.&n\r\n"; break; } break; } if (GameDay >= Limits.DAYS_PER_MONTH) { GameDay = 0; GameMonth++; } if (GameMonth >= Limits.MONTHS_PER_YEAR) { GameMonth = 0; GameYear++; } // Weather change. WeatherData.WindDirection += MUDMath.NumberRange(0, 2) - 1; int diff = 0; if (GameMonth >= 9 && GameMonth <= 16) { diff = WeatherData.BarometricPressure > 985 ? -2 : 2; } else { diff = WeatherData.BarometricPressure > 1015 ? -2 : 2; } WeatherData.Change += diff * MUDMath.Dice(1, 4) + MUDMath.Dice(2, 6) - MUDMath.Dice(2, 6); WeatherData.Change = Math.Max(WeatherData.Change, -12); WeatherData.Change = Math.Min(WeatherData.Change, 12); WeatherData.BarometricPressure += WeatherData.Change; WeatherData.BarometricPressure = Math.Max(WeatherData.BarometricPressure, 960); WeatherData.BarometricPressure = Math.Min(WeatherData.BarometricPressure, 1040); switch (WeatherData.Sky) { default: Log.Error("WeatherUpdate: bad sky {0}.", WeatherData.Sky); WeatherData.Sky = SkyType.clear; break; case SkyType.clear: if (WeatherData.BarometricPressure < 990 || (WeatherData.BarometricPressure < 1010 && MUDMath.NumberBits(2) == 0)) { if (GameMonth <= 3 || GameMonth >= 11) { text += "&+wA few &+Wf&n&+wl&+Wa&n&+wk&+We&n&+ws of &+Ws&n&+wn&+Wo&n&+ww&+w are falling&n.\r\n"; WeatherData.Temperature -= 10; } else { text += "&+LStorm clouds &n&+mthunder&+L in the distance&n.\r\n"; } WeatherData.Sky = SkyType.cloudy; WeatherData.WindSpeed += 10; } break; case SkyType.cloudy: if (WeatherData.BarometricPressure < 970 || (WeatherData.BarometricPressure < 990 && MUDMath.NumberBits(2) == 0)) { if (GameMonth <= 3 || GameMonth >= 11) { text += "&+wThe &+Wharsh s&n&+wn&+Wo&n&+ww-&+Lstorm&n&+w makes visibility difficult&n.\r\n"; WeatherData.Temperature -= 10; } else { text += "&+cSmall drops of &+Crain&n&+w m&+Wis&n&+wt the air&n.\r\n"; } WeatherData.Sky = SkyType.rain; WeatherData.WindSpeed += 10; } if (WeatherData.BarometricPressure > 1030 && MUDMath.NumberBits(2) == 0) { if (GameMonth <= 3 || GameMonth >= 11) { text += "&+wThe &+Wsnow&n&+w-&+Lstorm&n&+w seems to settle&n.\r\n"; WeatherData.Temperature += 10; } else { text += "&+cThe &+Cclouds&n&+c disappear from the skyline&n.\r\n"; } WeatherData.Sky = SkyType.clear; WeatherData.WindSpeed -= 10; } break; case SkyType.rain: if (WeatherData.BarometricPressure < 970 && MUDMath.NumberBits(2) == 0) { if (GameMonth <= 3 || GameMonth >= 11) { text += "&+wThe &+Wsnow-&+cstorm&n&+w has evolved into a full &+Cblizzard&n.\r\n"; WeatherData.Temperature -= 30; } else { text += "&+WLightning flashes across the sky&n.\r\n"; } WeatherData.Sky = SkyType.thunderstorm; WeatherData.WindSpeed += 10; } if (WeatherData.BarometricPressure > 1030 || (WeatherData.BarometricPressure > 1010 && MUDMath.NumberBits(2) == 0)) { if (GameMonth <= 3 || GameMonth >= 11) { text += "&+wThe &+Ws&n&+wn&+Wo&n&+ww seems to be letting up&n.\r\n"; WeatherData.Temperature += 30; } else { text += "&+cThe &+Crain&n&+c slows to a drizzle then quits&n.\r\n"; } WeatherData.Sky = SkyType.cloudy; WeatherData.WindSpeed -= 10; } break; case SkyType.thunderstorm: if (WeatherData.BarometricPressure > 1010 || (WeatherData.BarometricPressure > 990 && MUDMath.NumberBits(2) == 0)) { if (GameMonth <= 3 || GameMonth >= 11) { text += "&+wThe &+Wblizzard&n&+w subsides&n.\r\n"; WeatherData.Temperature += 10; } else { text += "&n&+wThe &+Lthunder &N&+wand &+Clightning&n&+w has stopped&N.\r\n"; } WeatherData.Sky = SkyType.rain; WeatherData.WindSpeed -= 10; break; } break; } if (text.Length > 0) { foreach (SocketConnection socket in Database.SocketList) { if (socket.ConnectionStatus == SocketConnection.ConnectionState.playing && socket.Character.IsOutside() && !socket.Character.IsUnderground() && socket.Character.IsAwake() && !socket.Character.InRoom.HasFlag(RoomTemplate.ROOM_NO_PRECIP)) { socket.Character.SendText(text); } } } foreach (SocketConnection playerSocket in Database.SocketList) { if ((playerSocket.ConnectionStatus == SocketConnection.ConnectionState.playing) && !playerSocket.Character.IsNPC()) { if (((PC)playerSocket.Character).FirstaidTimer > 0) { ((PC)playerSocket.Character).FirstaidTimer -= 1; } } } return; }
/// <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> /// Summoning an elemental. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="indexNumber"></param> public static void SummonElem(CharData ch, Spell spell, int level, int indexNumber) { int numpets = 0; foreach (CharData petChar in Database.CharList) { if (petChar != ch && petChar.Master == ch && petChar.IsNPC() && petChar.HasActionBit(MobTemplate.ACT_PET)) { numpets++; } } //just a WAG as far as number...check for some consistency with necro int maxpets = ch.Level / 20 + ch.GetCurrCha() / 35; if (ch.Level >= Limits.LEVEL_AVATAR) { string text = String.Format("You can summon at most {0} pets.\r\n", maxpets); ch.SendText(text); } if (numpets >= maxpets) { ch.SendText("You cannot handle any more pets!\r\n"); return; } CharData elemental = Database.CreateMobile(Database.GetMobTemplate(indexNumber)); elemental.AddToRoom(ch.InRoom); elemental.SetCoins(0, 0, 0, 0); elemental.Level = 27 + MUDMath.Dice(2, 5); elemental.MaxHitpoints = 150 + MUDMath.Dice(16, level / 2); elemental.Hitpoints = elemental.MaxHitpoints; elemental.ArmorPoints -= (ch.Level * 3 / 2); elemental.SetActionBit(MobTemplate.ACT_NOEXP); switch (indexNumber) { case StaticMobs.MOB_NUMBER_EARTH_PECH: SocketConnection.Act("$n&n rises from the ground before your eyes.", elemental, null, null, SocketConnection.MessageTarget.room); break; case StaticMobs.MOB_NUMBER_AIR_SLYPH: elemental.ArmorPoints = -130; elemental.PermAgility = 100; SocketConnection.Act("$n&n appears out of thin air.", elemental, null, null, SocketConnection.MessageTarget.room); break; case StaticMobs.MOB_NUMBER_FIRE_SERPENT: SocketConnection.Act("$n&n bursts into existence in a roaring ball of flame.", elemental, null, null, SocketConnection.MessageTarget.room); break; case StaticMobs.MOB_NUMBER_WATER_NEREID: SocketConnection.Act("$n&n coalesces into existence.", elemental, null, null, SocketConnection.MessageTarget.room); elemental.MaxHitpoints += 100; elemental.Hitpoints = elemental.MaxHitpoints; break; default: Log.Error("SummonElem: bad indexNumber in switch: " + indexNumber); ch.SendText("You managed to summon a bad indexNumber! Shame on you.\r\n"); break; } SocketConnection.Act("$N&n says 'Your wish is my command $n&n.'", ch, null, elemental, SocketConnection.MessageTarget.room); SocketConnection.Act("$N&n tells you 'Your wish is my command.'", ch, null, elemental, SocketConnection.MessageTarget.character); CharData.AddFollower(elemental, ch); elemental.Master = ch; Affect af = new Affect(Affect.AffectType.spell, spell.Name, level / 2 + MUDMath.Dice(4, level / 2), Affect.Apply.none, 0, Affect.AFFECT_CHARM); elemental.AddAffect(af); // Set the MobIndex.ACT_PET bit as well elemental.SetActionBit(MobTemplate.ACT_PET); elemental.FlightLevel = ch.FlightLevel; if (ch.Fighting) { Combat.SetFighting(elemental, ch.Fighting); } return; }