/// <summary> /// Song of chaos. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongChaos( CharData ch, Spell spell, int level, Target target ) { foreach( CharData victim in ch.InRoom.People ) { } return true; }
/// <summary> /// Song of calming. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongCalming( CharData ch, Spell spell, int level, Target target ) { foreach( CharData victim in ch.InRoom.People ) { Combat.StopFighting( victim, false ); victim.WaitState( 2 ); } return true; }
/// <summary> /// Song of armor. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongArmor( CharData ch, Spell spell, int level, Target target ) { ch.SendText( "You Sing a song of protection.\r\n" ); foreach( CharData victim in ch.InRoom.People ) { if (victim.IsAffected( Affect.AFFECT_ARMOR)) continue; Affect af = new Affect( Affect.AffectType.song, spell.Name, 4, Affect.Apply.ac, ( 0 - ( 10 + ( level / 5 ) ) ), Affect.AFFECT_ARMOR ); victim.CombineAffect( af ); victim.SendText( "You feel someone protecting you.\r\n" ); } return true; }
public static bool CompileSpell(Spell spell) { CSharpCodeProvider prov = new CSharpCodeProvider(); CompilerParameters cp = new CompilerParameters(); cp.GenerateExecutable = true; cp.GenerateInMemory = true; cp.ReferencedAssemblies.Add("System.dll"); cp.ReferencedAssemblies.Add("System.Xml.dll"); cp.ReferencedAssemblies.Add("MUDEngine.dll"); cp.ReferencedAssemblies.Add("ZoneData.dll"); Log.Trace("Compiling spell '" + spell.Name + "'."); StringBuilder sb = new StringBuilder(); int idx = spell.FileName.IndexOf('.'); string file = spell.FileName; if (idx > 0) { file = spell.FileName.Substring(0, idx); } int lines = GenerateWithMain(sb, spell.Code, "MUDEngine"); CompilerResults cr = prov.CompileAssemblyFromSource(cp,sb.ToString()); if (cr.Errors.HasErrors) { StringBuilder sbErr = new StringBuilder("Compiling Spell: "); sbErr.AppendFormat("\"{0}\" in file \"{1}\".", spell.Name, spell.FileName); sbErr.Append("\n\n"); foreach (CompilerError err in cr.Errors) { // Add 13 lines to the line number to get us the *actual* line number of the code. sbErr.AppendFormat("{0} at code line {1} column {2}.", err.ErrorText, err.Line - 13, err.Column); sbErr.Append("\n"); } Log.Error(sbErr.ToString()); Log.Info("Spell code is:\n" + spell.Code); return false; } spell.CompiledCode = cr.CompiledAssembly; Log.Trace("Compile successful."); return true; }
/// <summary> /// Song of nightmares. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongNightmares( CharData ch, Spell spell, int level, Target target ) { Affect af = new Affect(); foreach( CharData victim in ch.InRoom.People ) { if (victim.IsAffected(Affect.AFFECT_FEAR) || Magic.SpellSavingThrow(level, victim, AttackType.DamageType.black_magic ) ) { ch.SendText( "You have failed.\r\n" ); ch.SendText( "You resist the urge to panic.\r\n" ); continue; } af.Type = Affect.AffectType.song; af.Value = spell.Name; af.Duration = 1 + ( level / 7 ); af.SetBitvector( Affect.AFFECT_FEAR ); victim.AddAffect(af); SocketConnection.Act( "$N&n is scared!", ch, null, victim, SocketConnection.MessageTarget.character ); victim.SendText( "You are scared!\r\n" ); SocketConnection.Act( "$N&n is scared!", ch, null, victim, SocketConnection.MessageTarget.everyone_but_victim ); CommandType.Interpret( victim, "flee" ); if( victim.IsNPC() ) Combat.StartFearing( victim, ch ); } return true; }
/// <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> /// Song of invisibility. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongInvisibility( CharData ch, Spell spell, int level, Target target ) { int total = 0; int max = level / 8; foreach( CharData victim in ch.InRoom.People ) { if( !victim.IsSameGroup( ch ) || victim.IsAffected( Affect.AFFECT_INVISIBLE ) ) continue; if( total >= max ) return true; victim.SendText( "You slowly fade out of existence.\r\n" ); SocketConnection.Act( "$n&n slowly fades out of existence.", victim, null, null, SocketConnection.MessageTarget.room ); Affect af = new Affect(Affect.AffectType.song, spell.Name, (level / 6), Affect.Apply.none, 0, Affect.AFFECT_INVISIBLE); victim.AddAffect(af); total++; } foreach( Object obj in ch.InRoom.Contents ) { if( obj.HasFlag( ObjTemplate.ITEM_INVIS ) ) continue; if( total >= max ) return true; SocketConnection.Act( "&+L$p&+L fades away.", ch, obj, null, SocketConnection.MessageTarget.room ); SocketConnection.Act( "&+L$p&+L fades away.", ch, obj, null, SocketConnection.MessageTarget.character ); obj.AddFlag( ObjTemplate.ITEM_INVIS ); total++; } return true; }
/// <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> /// A slightly simplified version of the spell-based HasLevelForSpell() _function. This should probably /// not be used until we can guarantee that spell names are reliable. It skips the reference to /// the spell table so is infinitesimally more efficient. /// </summary> /// <param name="spell"></param> /// <returns></returns> private bool HasLevelForSpell(Spell spell) { foreach (SpellEntry se in CharacterClass.Spells) { if( se.Name == spell.Name ) { if( Level >= (se.Circle * 4 - 3) ) { return true; } return false; } } return false; }
/// <summary> /// Song of revelation. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongRevelation( CharData ch, Spell spell, int level, Target target ) { foreach( CharData victim in ch.InRoom.People ) { victim.AffectStrip( Affect.AffectType.skill, "shadow form"); victim.RemoveAffect(Affect.AFFECT_HIDE); victim.RemoveAffect(Affect.AFFECT_INVISIBLE); SocketConnection.Act( "$n&n is revealed!", victim, null, null, SocketConnection.MessageTarget.room ); victim.SendText( "You are revealed!\r\n" ); } return true; }
/// <summary> /// Song of slowness. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongSlowness( CharData ch, Spell spell, int level, Target target ) { Affect af = new Affect(); foreach( CharData victim in ch.InRoom.People ) { if( Magic.SpellSavingThrow( level, victim, AttackType.DamageType.magic_other ) ) { ch.SendText( "You failed!\r\n" ); continue; } // Removes haste, takes two castings to make a hasted person slowed if (victim.IsAffected( Affect.AFFECT_HASTE)) { victim.RemoveAffect(Affect.AFFECT_HASTE); victim.SendText( "You slow to your normal speed.\r\n" ); continue; } if (victim.IsAffected(Affect.AFFECT_SLOWNESS)) continue; af.Type = Affect.AffectType.song; af.Value = spell.Name; af.Duration = 6; af.SetBitvector( Affect.AFFECT_SLOWNESS ); victim.AddAffect(af); SocketConnection.Act( "&+R$n&+R moves much more slowly.&n", victim, null, null, SocketConnection.MessageTarget.room ); victim.SendText( "&+RYou feel yourself slowing down.&n\r\n" ); } return true; }
/// <summary> /// Song of cowardice. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongCowardice( CharData ch, Spell spell, int level, Target target ) { foreach( CharData victim in ch.InRoom.People ) { if( !victim.IsSameGroup( ch ) ) { Affect af = new Affect(Affect.AffectType.song, spell.Name, (level / 6 + 1), Affect.Apply.hitroll, (0 - (level / 3)), Affect.AFFECT_COWARDLY); victim.AddAffect(af); SocketConnection.Act( "$n&n looks unsure of $mself.", victim, null, null, SocketConnection.MessageTarget.room ); victim.SendText( "You feel less confident about your battle skills.\r\n" ); } } return true; }
/// <summary> /// Song of feasting. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongFeasting( CharData ch, Spell spell, int level, Target target ) { foreach( CharData victim in ch.InRoom.People ) { if( victim.IsNPC() ) continue; int amount = level / 7 + 1; if( ( (PC)victim ).Hunger < 48 ) ( (PC)victim ).Hunger += amount; if( ( (PC)victim ).Thirst < 48 ) ( (PC)victim ).Thirst += amount; victim.SendText( "You stomach feels fuller.\r\n" ); } return true; }
static void SendSpellDamageMessage( CharData ch, CharData victim, int dam, Spell spell, bool immune ) { string attack = String.Empty; string buf1; string buf2; string buf3; string buf4; string buf5; if( dam < 0 ) { Log.Error( "SendSpellDamageMessage: Negative damage from spell {0}", spell.Name ); dam = 0; } if( spell != null ) attack = spell.Name; if( immune ) { buf1 = String.Format( "$N&n seems unaffected by your {0}!", attack ); buf2 = String.Format( "$n&n's {0} seems powerless against you.", attack ); buf3 = String.Format( "$N&n seems unaffected by $n&n's {0}!", attack ); buf4 = String.Format( "Luckily, you are immune to your {0}.", attack ); buf5 = String.Format( "$n&n seems unaffected by $s own {0}.", attack ); } else if( dam == 0 ) { buf1 = String.Format( "Your {0} misses $N&n.", attack ); buf2 = String.Format( "$n&n's {0} misses you.", attack ); buf3 = String.Format( "$N&n avoids being hit by $n&n's {0}!", attack ); buf5 = String.Format( "Luckily, you are not hit by your {0}.", attack ); buf4 = String.Format( "$n&n fails to hit $mself with $s own {0}.", attack ); } else { buf1 = String.Format( spell.MessageDamage ); buf2 = String.Format( spell.MessageDamageToVictim); buf3 = String.Format(spell.MessageDamageToRoom); buf4 = String.Format(spell.MessageDamageToSelf); buf5 = String.Format(spell.MessageDamageSelfToRoom); } if( victim != ch ) { SocketConnection.Act( buf1, ch, null, victim, SocketConnection.MessageTarget.character ); SocketConnection.Act( buf2, ch, null, victim, SocketConnection.MessageTarget.victim ); SocketConnection.Act( buf3, ch, null, victim, SocketConnection.MessageTarget.room_vict ); } else { SocketConnection.Act( buf4, ch, null, victim, SocketConnection.MessageTarget.character ); SocketConnection.Act( buf5, ch, null, victim, SocketConnection.MessageTarget.room ); } return; }
/// <summary> /// Immortal command to set or display game-wide configuration settings. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void MudConfig(CharData ch, string[] str) { if( ch == null ) return; CharData realChar = ch.GetChar(); if (!realChar.Authorized("world")) return; if (str.Length == 0) { ch.SendText("&+L+--------------+----------------------------------------------------------+&n\r\n"); ch.SendText("&+L|&n&+m Option&+L |&n&+r Description&n &+L|&n\r\n"); ch.SendText("&+L+--------------+----------------------------------------------------------+&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.newlock) ? "&+L[&+WX&+L]&n Newlock &+L|&+c The mud is locked to new players. &+L|&n\r\n" : "&+L[ ]&n Newlock &+L|&+c The mud allows new players. &+L|&n\r\n" ); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.turbolevel) ? "&+L[&+WX&+L]&n Turbolevel &+L|&+c Players get up to 10 levels at a time. &+L|&n\r\n" : "&+L[ ]&n Turbolevel &+L|&+c Players level as normal. &+L|&n\r\n" ); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.equipmentdamage) ? "&+L[&+WX&+L]&n Eqdamage &+L|&+c Equipment will take damage. &+L|&n\r\n" : "&+L[ ]&n Eqdamage &+L|&+c Equipment is practically indestructible. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.capturetheflag) ? "&+L[&+WX&+L]&n CTF &+L|&+c Capture the flag is enabled. &+L|&n\r\n" : "&+L[ ]&n CTF &+L|&+c Capture the flag is not enabled. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.equipmentpvp) ? "&+L[&+WX&+L]&n EqPVP &+L|&+c Equipment effects ability in PvP and stealing (NYI). &+L|&n\r\n" : "&+L[ ]&n EqPVP &+L|&+c Equipment doesn't effect PvP and stealing (NYI). &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.stricteqpvp) ? "&+L[&+WX&+L]&n StrictEQ &+L|&+c Strict equipment PvP requirements. &+L|&n\r\n" : "&+L[ ]&n StrictEQ &+L|&+c Lenient equipment PvP requirements. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.mobcastslots) ? "&+L[&+WX&+L]&n Mobcast &+L|&+c Mobs use slots for spellcasting. &+L|&n\r\n" : "&+L[ ]&n Mobcast &+L|&+c Mobs have unlimited spells. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.mobslootplayers) ? "&+L[&+WX&+L]&n Mobloot &+L|&+c Mobs will loot PC corpses. &+L|&n\r\n" : "&+L[ ]&n Mobloot &+L|&+c Mobs will not loot PC corpses. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.autoprice) ? "&+L[&+WX&+L]&n Autoprice &+L|&+c The MUD overrides prices set on EQ in the area file. &+L|&n\r\n" : "&+L[ ]&n Autoprice &+L|&+c The MUD doesn't override EQ prices in the area file. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.walkableocean) ? "&+L[&+WX&+L]&n Walkocean &+L|&+c Players can walk on the ocean. (NYI) &+L|&n\r\n" : "&+L[ ]&n Walkocean &+L|&+c Players can't travel the ocean without a boat. (NYI). &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.powerlevel) ? "&+L[&+WX&+L]&n Plevel &+L|&+c Power leveling is enabled. &+L|&n\r\n" : "&+L[ ]&n Plevel &+L|&+c Power leveling is disabled. &+L|&n\r\n"); ch.SendText(CommandType.fLogAll ? "&+L[&+WX&+L]&n Logall &+L|&+c The MUD logs every command. &+L|&n\r\n" : "&+L[ ]&n Logall &+L|&+c The MUD does not log all commands. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.candelete) ? "&+L[&+WX&+L]&n Candelete &+L|&+c Players can delete their characters. &+L|&n\r\n" : "&+L[ ]&n Candelete &+L|&+c Players cannot delete their characters. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.levelrestrictedeq) ? "&+L[&+WX&+L]&n Eqrestrict &+L|&+c Players cannot use equipment 25+ levels above them. &+L|&n\r\n" : "&+L[ ]&n Eqrestrict &+L|&+c Players can use equipment of any level. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.nameapproval) ? "&+L[&+WX&+L]&n Nameapprove&+L|&+c Players have to wait for name approval. &+L|&n\r\n" : "&+L[ ]&n Nameapprove&+L|&+c Players don't have to wait for name approval. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.disablemccp) ? "&+L[&+WX&+L]&n DisableMCCP&+L|&+c MCCP is disabled MUD-wide. &+L|&n\r\n" : "&+L[ ]&n DisableMCCP&+L|&+c The MUD supports MCCP. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.disablemsp) ? "&+L[&+WX&+L]&n DisableMSP &+L|&+c The MUD Sound Protocol (MSP) is disabled MUD-wide. &+L|&n\r\n" : "&+L[ ]&n DisableMSP &+L|&+c The MUD supports MSP. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.disablefaction) ? "&+L[&+WX&+L]&n Faction &+L|&+c Faction is disabled. &+L|&n\r\n" : "&+L[ ]&n Faction &+L|&+c Faction is enabled. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.checkfactionbit) ? "&+L[&+WX&+L]&n Factionbit &+L|&+c Checking of faction bit on mobs is enabled. &+L|&n\r\n" : "&+L[ ]&n Factionbit &+L|&+c Checking of faction bit on mobs is disabled. &+L|&n\r\n"); ch.SendText(Macros.IsSet((int)Database.SystemData.ActFlags, (int)Sysdata.MudFlags.alwaysequip) ? "&+L[&+WX&+L]&n Alwaysequip&+L|&+c Players always get newbie equipment when they die. &+L|&n\r\n" : "&+L[ ]&n Alwaysequip&+L|&+c Players over lvl 5 don't get newbie eq after death. &+L|&n\r\n"); ch.SendText("&+L+--------------+----------------------------------------------------------+&n\r\n"); ch.SendText("World save to save sysdata, the fraglist, corpses, and crimes.\r\n"); ch.SendText("World stat to show mud stats.\r\n"); } else { string text; Sysdata.MudFlags bit; bool setting; if (str[0][0] == '+') { setting = true; } else if (str[0][0] == '-') { setting = false; } else { if (!MUDString.StringsNotEqual(str[0], "save")) { Sysdata.Save(); FraglistData.Fraglist.Save(); Database.CorpseList.Save(); Crime.Save(); ch.SendText("Sysdata, Fraglist, Corpses, and Crimes saved.\r\n"); return; } if (!MUDString.StringsNotEqual(str[0], "stat")) { ch.SendText(String.Format("Players: {0} MaxPlayers: {1}\r\n", MUDString.PadInt(Database.SystemData.NumPlayers, 5), MUDString.PadInt(Database.SystemData.MaxPlayers, 5))); ch.SendText(String.Format("MaxEver: {0} Recorded at: {1}\r\n", MUDString.PadInt(Database.SystemData.MaxPlayersEver, 5), Database.SystemData.MaxPlayersTime)); ch.SendText(String.Format("Mobs: {0} MobTemplates: {1}\r\n", MUDString.PadInt(CharData.Count, 5), MUDString.PadInt(MobTemplate.Count, 5))); ch.SendText(String.Format("Rooms: {0}\r\n", MUDString.PadInt(RoomTemplate.Count, 5))); ch.SendText(String.Format("Objects: {0} ObjTemplates: {1}\r\n", MUDString.PadInt(Object.Count, 5), MUDString.PadInt(ObjTemplate.Count, 5))); ch.SendText(String.Format("Shops: {0}\r\n", MUDString.PadInt(Shop.Count, 5))); ch.SendText(String.Format("Traps: {0}\r\n", MUDString.PadInt(Trap.Count, 5))); ch.SendText(String.Format("Skills: {0}\r\n", MUDString.PadInt(Skill.Count, 5))); ch.SendText(String.Format("Spells: {0}\r\n", MUDString.PadInt(Spell.Count, 5))); ch.SendText(String.Format("Resets: {0}\r\n", MUDString.PadInt(Reset.Count, 5))); ch.SendText(String.Format("Races: {0}\r\n", MUDString.PadInt(Race.Count, 5))); ch.SendText(String.Format("Exits: {0}\r\n", MUDString.PadInt(Exit.Count, 5))); ch.SendText(String.Format("Classes: {0}\r\n", MUDString.PadInt(CharClass.Count, 5))); ch.SendText(String.Format("Areas: {0}\r\n", MUDString.PadInt(Area.Count, 5))); ch.SendText(String.Format("Affects: {0}\r\n", MUDString.PadInt(Affect.Count, 5))); ch.SendText(String.Format("Bounties:{0}\r\n", MUDString.PadInt(Bounty.Count, 5))); ch.SendText(String.Format("QuestTemplates: {0}\r\n", MUDString.PadInt(QuestTemplate.Count, 5))); ch.SendText(String.Format("QuestItems: {0}\r\n", MUDString.PadInt(QuestItem.Count, 5))); ch.SendText(String.Format("QuestData: {0}\r\n", MUDString.PadInt(QuestData.Count, 5))); Assembly assembly = Assembly.GetExecutingAssembly(); AssemblyCopyrightAttribute copyright = (AssemblyCopyrightAttribute)AssemblyCopyrightAttribute.GetCustomAttribute( assembly, typeof(AssemblyCopyrightAttribute)); AssemblyTitleAttribute title = (AssemblyTitleAttribute)AssemblyTitleAttribute.GetCustomAttribute( assembly, typeof(AssemblyTitleAttribute)); FileInfo info = new FileInfo(assembly.Location); DateTime date = info.LastWriteTime; // Create a bitvector class just so we can get info about the base assembly. Bitvector bv = new Bitvector(); string baseName = bv.GetType().Assembly.GetName().Name; string baseVersion = bv.GetType().Assembly.GetName().Version.ToString(); FileInfo baseInfo = new FileInfo(bv.GetType().Assembly.Location); DateTime baseDate = baseInfo.LastWriteTime; Spell spell = new Spell(); string baseName2 = spell.GetType().Assembly.GetName().Name; string baseVersion2 = spell.GetType().Assembly.GetName().Version.ToString(); FileInfo baseInfo2 = new FileInfo(spell.GetType().Assembly.Location); DateTime baseDate2 = baseInfo2.LastWriteTime; string version = title.Title + " version " + assembly.GetName().Version + " built on " + date.ToShortDateString() + ".\r\nBased on version " + baseVersion + " of " + baseName + " built on " + baseDate.ToShortDateString() + ".\r\nBased on version " + baseVersion2 + " of " + baseName2 + " built on " + baseDate2.ToShortDateString() + "\r\n"; ch.SendText(version); return; } ch.SendText("World -option or +option?\r\n"); ch.SendText("or: save \r\n"); ch.SendText("or: stat \r\n"); return; } string tmparg = str[0]; if ("newlock".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.newlock; else if ("turbolevel".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.turbolevel; else if ("eqdamage".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.equipmentdamage; else if ("ctf".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.capturetheflag; else if ("eqpvp".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.equipmentpvp; else if ("mobloot".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.mobslootplayers; else if ("walkocean".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.walkableocean; else if ("autoprice".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.autoprice; else if ("stricteq".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.stricteqpvp; else if ("mobcast".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.mobcastslots; else if ("plevel".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.powerlevel; else if ("eqrestrict".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.levelrestrictedeq; else if ("nameapprove".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.nameapproval; else if ("candelete".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.candelete; else if ("disablemccp".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.disablemccp; else if ("disablemsp".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.disablemsp; else if ("faction".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.disablefaction; else if ("factionbit".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.checkfactionbit; else if ("alwaysequip".StartsWith(tmparg.Substring(1), StringComparison.CurrentCultureIgnoreCase)) bit = Sysdata.MudFlags.alwaysequip; else { ch.SendText("World which option?\r\n"); return; } // Convert to int so we can use SET_BIT. int flags = (int)Database.SystemData.ActFlags; if (setting) { Macros.SetBit(ref flags, (int)bit); text = String.Format("{0} is now ON.\r\n", tmparg); ch.SendText(text.ToUpper()); } else { Macros.RemoveBit(ref flags, (int)bit); text = String.Format("{0} is now OFF.\r\n", tmparg); ch.SendText(text.ToUpper()); } // Store modified value in our act flags. Database.SystemData.ActFlags = (Sysdata.MudFlags)flags; } return; }
/// <summary> /// Inflicts damage from a spell, based on the weapon damage() function, but customized for spells. /// /// Needs to be cleaned up because it's just too big (600+ lines). /// </summary> /// <param name="ch"></param> /// <param name="victim"></param> /// <param name="dam"></param> /// <param name="spell"></param> /// <param name="damType"></param> /// <returns></returns> public static bool InflictSpellDamage( CharData ch, CharData victim, int dam, Spell spell, AttackType.DamageType damType ) { if( ch == null || victim == null || victim.CurrentPosition == Position.dead ) return true; // Remove memorization and meditation bits. // And invis. ch.BreakInvisibility(); victim.BreakMeditate(); victim.BreakMemorization(); if( CheckShrug( ch, victim ) ) return false; if( victim.CurrentPosition == Position.sleeping && !( victim.GetRace() == Race.RACE_FIRE_ELE && damType == AttackType.DamageType.fire ) && !( victim.GetRace() == Race.RACE_WATER_ELE && damType == AttackType.DamageType.water ) && !( victim.GetRace() == Race.RACE_EARTH_ELE && damType == AttackType.DamageType.earth ) && !( victim.GetRace() == Race.RACE_AIR_ELE && damType == AttackType.DamageType.wind ) ) { SocketConnection.Act( "$n&n has a rude awakening!", victim, null, null, SocketConnection.MessageTarget.room ); victim.CurrentPosition = Position.resting; if( ch.InRoom == victim.InRoom && ch.FlightLevel == victim.FlightLevel ) SetFighting( victim, ch ); } // Check for globe spells. See also FinishSpell under TargetType.singleCharacterOffensive // This check here is just to prevent area effect spells from // doing damage if too low level. The check for direct spells is in // Magic.cs if (victim.IsAffected( Affect.AFFECT_MAJOR_GLOBE) && (spell.SpellCircle[(int)ch.CharacterClass.ClassNumber] <= 6 || spell.Name == "fireshield" || spell.Name == "shockshield" || spell.Name == "soulshield" || spell.Name == "coldshield" ) ) { SocketConnection.Act( "&+RThe globe around $N&+R's body bears the brunt of your assault!&n", ch, null, victim, SocketConnection.MessageTarget.character ); SocketConnection.Act( "&+RYour globe deflects $n&+R's attack!&n", ch, null, victim, SocketConnection.MessageTarget.victim ); SocketConnection.Act( "&+R$N&+R's globe deflects $n&+R's attack!&n", ch, null, victim, SocketConnection.MessageTarget.room_vict ); return false; } if (victim.IsAffected( Affect.AFFECT_GREATER_SPIRIT_WARD) && spell.SpellCircle[(int)ch.CharacterClass.ClassNumber] <= 5) { SocketConnection.Act( "&+WThe aura around $N&+W's body bears the brunt of your assault!&n", ch, null, victim, SocketConnection.MessageTarget.character ); SocketConnection.Act( "&+WYour globe absorbs $n&+W's attack!&n", ch, null, victim, SocketConnection.MessageTarget.victim ); SocketConnection.Act( "&+W$N&+W's aura absorbs $n&+W's attack!&n", ch, null, victim, SocketConnection.MessageTarget.room_vict ); return false; } if (victim.IsAffected( Affect.AFFECT_MINOR_GLOBE) && spell.SpellCircle[(int)ch.CharacterClass.ClassNumber] <= 4) { SocketConnection.Act( "&+RThe globe around $N&+R's body bears the brunt of your assault!&n", ch, null, victim, SocketConnection.MessageTarget.character ); SocketConnection.Act( "&+RYour globe deflects $n&+R's attack!&n", ch, null, victim, SocketConnection.MessageTarget.victim ); SocketConnection.Act( "&+R$N&+R's globe deflects $n&+R's attack!&n", ch, null, victim, SocketConnection.MessageTarget.room_vict ); return false; } if (victim.IsAffected( Affect.AFFECT_SPIRIT_WARD) && spell.SpellCircle[(int)ch.CharacterClass.ClassNumber] <= 3) { SocketConnection.Act( "&+WThe aura around $N&+W's body bears the brunt of your assault!&n", ch, null, victim, SocketConnection.MessageTarget.character ); SocketConnection.Act( "&+WYour globe absorbs $n&+W's attack!&n", ch, null, victim, SocketConnection.MessageTarget.victim ); SocketConnection.Act( "&+W$N&+W's aura absorbs $n&+W's attack!&n", ch, null, victim, SocketConnection.MessageTarget.victim ); return false; } /* * Stop up any residual loopholes. */ // 1275 is average damage from Akiaurn's Power Word // I changed this to reflect that. if( ( dam > 1275 ) && ch.Level < Limits.LEVEL_AVATAR && ch.GetRace() != Race.RACE_DRAGON ) { string buf3; if( ch.IsNPC() && ch.Socket ) buf3 = String.Format( "Spell_Damage: {0} from {1} by {2}: > 1275 points with {3} spell!", dam, ch.Name, ch.Socket.Original.Name, spell.Name ); else buf3 = String.Format( "Spell_Damage: {0} from {1}: > 1275 points with {2} spell!", dam, ch.IsNPC() ? ch.ShortDescription : ch.Name, spell.Name ); Log.Error( buf3, 0 ); dam = 1275; } if (victim.IsAffected( Affect.AFFECT_MINOR_PARA) && !( victim.GetRace() == Race.RACE_FIRE_ELE && damType == AttackType.DamageType.fire ) && !( victim.GetRace() == Race.RACE_WATER_ELE && damType == AttackType.DamageType.water ) && !( victim.GetRace() == Race.RACE_EARTH_ELE && damType == AttackType.DamageType.earth ) && !( victim.GetRace() == Race.RACE_AIR_ELE && damType == AttackType.DamageType.wind ) ) { SocketConnection.Act( "$n&n disrupts the magic preventing $N&n from moving.", ch, null, victim, SocketConnection.MessageTarget.room_vict ); SocketConnection.Act( "You disrupt the magic preventing $N&n from moving.", ch, null, victim, SocketConnection.MessageTarget.character ); SocketConnection.Act( "&+YYou can move again.&n", ch, null, victim, SocketConnection.MessageTarget.victim ); victim.RemoveAffect( Affect.AFFECT_MINOR_PARA ); victim.AffectStrip( Affect.AffectType.spell, "earthen grasp" ); victim.AffectStrip( Affect.AffectType.spell, "greater earthen grasp"); } bool immune = false; if( victim != ch ) { /* * Certain attacks are forbidden. * Most other attacks are returned. */ 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 true; Crime.CheckAttemptedMurder( ch, victim ); if( victim.CurrentPosition > Position.stunned && !( victim.GetRace() == Race.RACE_FIRE_ELE && damType == AttackType.DamageType.fire ) && !( victim.GetRace() == Race.RACE_WATER_ELE && damType == AttackType.DamageType.water ) && !( victim.GetRace() == Race.RACE_EARTH_ELE && damType == AttackType.DamageType.earth ) && !( victim.GetRace() == Race.RACE_AIR_ELE && damType == AttackType.DamageType.wind ) ) { // Offensive spells engage victim if not fighting, and // caster only if neither are fighting. if( !victim.Fighting && victim.InRoom == ch.InRoom && victim.FlightLevel == ch.FlightLevel ) { SetFighting( victim, ch ); if( !ch.Fighting ) SetFighting( ch, victim ); // Can't have prone people automaticaly stand. if( victim.CurrentPosition == Position.standing ) victim.CurrentPosition = Position.fighting; } /* * If NPC victim is following, ch might attack victim's master. * No charm check here because charm would be dispelled from * tanking mobile when combat ensues thus ensuring PC charmer is * not harmed. * Check for is_same_group wont work as following mobile is not * always grouped with PC charmer */ if( ch.IsNPC() && victim.IsNPC() && victim.Master && victim.Master.InRoom == ch.InRoom && MUDMath.NumberBits( 2 ) == 0 ) { StopFighting( ch, false ); SetFighting( ch, victim.Master ); return false; } } /* * More charm stuff. */ if( victim.Master == ch && !( victim.GetRace() == Race.RACE_FIRE_ELE && damType == AttackType.DamageType.fire ) && !( victim.GetRace() == Race.RACE_WATER_ELE && damType == AttackType.DamageType.water ) && !( victim.GetRace() == Race.RACE_EARTH_ELE && damType == AttackType.DamageType.earth ) && !( victim.GetRace() == Race.RACE_AIR_ELE && damType == AttackType.DamageType.wind ) ) StopFighting( victim, true ); /* * Hunting stuff... */ if( dam != 0 && victim.IsNPC() && !( victim.GetRace() == Race.RACE_FIRE_ELE && damType == AttackType.DamageType.fire ) && !( victim.GetRace() == Race.RACE_WATER_ELE && damType == AttackType.DamageType.water ) && !( victim.GetRace() == Race.RACE_EARTH_ELE && damType == AttackType.DamageType.earth ) && !( victim.GetRace() == Race.RACE_AIR_ELE && damType == AttackType.DamageType.wind ) ) { StartGrudge( victim, ch, false ); } /* * Damage modifiers. */ if (victim.IsAffected( Affect.AFFECT_SANCTUARY)) dam /= 2; if ((victim.IsAffected( Affect.AFFECT_PROTECT_EVIL)) && ch.IsEvil()) dam -= dam / 8; else if ((victim.IsAffected( Affect.AFFECT_PROTECT_GOOD)) && ch.IsGood()) dam -= dam / 8; if( dam < 0 ) dam = 0; } switch( victim.CheckRIS( damType ) ) { case Race.ResistanceType.resistant: dam -= dam / 3; break; case Race.ResistanceType.immune: immune = true; dam = 0; break; case Race.ResistanceType.susceptible: dam += dam / 2; break; case Race.ResistanceType.vulnerable: dam *= 2; break; } if( ( damType == AttackType.DamageType.wind || damType == AttackType.DamageType.gas || damType == AttackType.DamageType.asphyxiation ) && victim.IsAffected( Affect.AFFECT_DENY_AIR)) { if( MUDMath.NumberPercent() < 50 ) { victim.SendText( "&+CYou deny the damage.&n\r\n" ); immune = true; dam = 0; } else dam -= dam / 5; } if (damType == AttackType.DamageType.fire && victim.IsAffected( Affect.AFFECT_DENY_FIRE)) { if( MUDMath.NumberPercent() < 50 ) { victim.SendText( "&+rYou deny the damage.&n\r\n" ); immune = true; dam = 0; } else dam -= dam / 5; } if( ( damType == AttackType.DamageType.earth || damType == AttackType.DamageType.crushing ) && victim.IsAffected(Affect.AFFECT_DENY_EARTH)) { if( MUDMath.NumberPercent() < 50 ) { victim.SendText( "&+yYou deny the damage.&n\r\n" ); immune = true; dam = 0; } else dam -= dam / 5; } if( ( damType == AttackType.DamageType.water || damType == AttackType.DamageType.acid || damType == AttackType.DamageType.drowning ) && victim.IsAffected(Affect.AFFECT_DENY_WATER)) { if( MUDMath.NumberPercent() < 50 ) { victim.SendText( "&+bYou deny the damage.&n\r\n" ); immune = true; dam = 0; } else dam -= dam / 5; } // Check for protection spells that give 25% damage reduction - Xangis if (damType == AttackType.DamageType.fire && victim.IsAffected( Affect.AFFECT_PROTECT_FIRE)) dam = ( dam * 3 ) / 4; else if (damType == AttackType.DamageType.cold && victim.IsAffected( Affect.AFFECT_PROTECT_COLD)) dam = ( dam * 3 ) / 4; else if (damType == AttackType.DamageType.acid && victim.IsAffected( Affect.AFFECT_PROTECT_ACID)) dam = ( dam * 3 ) / 4; else if (damType == AttackType.DamageType.gas && victim.IsAffected( Affect.AFFECT_PROTECT_GAS)) dam = ( dam * 3 ) / 4; else if (damType == AttackType.DamageType.electricity && victim.IsAffected( Affect.AFFECT_PROTECT_LIGHTNING)) dam = ( dam * 3 ) / 4; /* * We moved DamageMessage out of the victim != ch if above * so self damage would show. Other valid type_undefined * damage is ok to avoid like mortally wounded damage */ if( spell != Spell.SpellList["reserved"] && !( victim.GetRace() == Race.RACE_FIRE_ELE && damType == AttackType.DamageType.fire ) && !( victim.GetRace() == Race.RACE_WATER_ELE && damType == AttackType.DamageType.water ) && !( victim.GetRace() == Race.RACE_EARTH_ELE && damType == AttackType.DamageType.earth ) && !( victim.GetRace() == Race.RACE_AIR_ELE && damType == AttackType.DamageType.wind ) ) SendSpellDamageMessage( ch, victim, dam, spell, immune ); /* PC to PC damage quartered. * NPC to PC damage divided by 3. */ if( dam > 0 && !victim.IsNPC() && victim != ch ) { if( !ch.IsNPC() ) dam /= 4; else dam /= 3; } /* * Hurt the victim. * Inform the victim of his new state. */ if( !( victim.GetRace() == Race.RACE_FIRE_ELE && damType == AttackType.DamageType.fire ) && !( victim.GetRace() == Race.RACE_WATER_ELE && damType == AttackType.DamageType.water ) && !( victim.GetRace() == Race.RACE_EARTH_ELE && damType == AttackType.DamageType.earth ) && !( victim.GetRace() == Race.RACE_AIR_ELE && damType == AttackType.DamageType.wind ) ) { /* Added damage exp! */ // chance added because people level faster and faster as they get higher level... // you can now only get damage exp on mobs that con easy or better // and there's only a 25% chance per hit of you evern being eligible for damage exp. if( MUDMath.NumberPercent() < 25 && victim.Level >= ( ch.Level - 3 ) ) ch.GainExperience( Math.Max( 1, dam / 20 ) ); victim.Hitpoints -= dam; } else { string attack; if( spell != null && spell != Spell.SpellList["none"] ) attack = spell.Name; else attack = "it"; SocketConnection.Act( "$N&n absorbs your $t!", ch, attack, victim, SocketConnection.MessageTarget.character ); SocketConnection.Act( "You absorb $n&n's $t!", ch, attack, victim, SocketConnection.MessageTarget.victim ); SocketConnection.Act( "$N&n absorbs $n&n's $t", ch, attack, victim, SocketConnection.MessageTarget.room_vict ); if( ch.IsImmortal() ) { string buf4 = String.Format( "You healed {0} damage.", victim.GetMaxHit() >= dam + victim.Hitpoints ? dam : victim.GetMaxHit() - victim.Hitpoints ); ch.SendText( buf4 ); } victim.Hitpoints = Math.Min( victim.GetMaxHit(), victim.Hitpoints + dam ); return false; } if( !victim.IsNPC() && victim.Level >= Limits.LEVEL_AVATAR && victim.Hitpoints < 1 ) victim.Hitpoints = 1; if (victim.IsAffected(Affect.AFFECT_BERZERK) && victim.CurrentPosition <= Position.stunned ) victim.RemoveAffect(Affect.AFFECT_BERZERK); victim.UpdatePosition(); switch( victim.CurrentPosition ) { case Position.mortally_wounded: victim.SendText( "&+LYou are &+Rmo&n&+rr&+Rt&n&+ral&+Rl&n&+ry&+L wounded, and will die soon, if not aided.&n\r\n" ); SocketConnection.Act( "$n&+L is &+Rmo&n&+rr&+Rt&n&+ral&+Rl&n&+ry&+L wounded, and will die soon, if not aided.&n", victim, null, null, SocketConnection.MessageTarget.room, true ); StopNotVicious( victim ); break; case Position.incapacitated: victim.SendText( "&+LYou are incapacitated and will slowly &n&+rbl&+Re&n&+re&+Rd&+L to death, if not aided.\r\n" ); SocketConnection.Act( "$n&+L is incapacitated and will slowly &n&+rbl&+Re&n&+re&+Rd&+L to death, if not aided.&n", victim, null, null, SocketConnection.MessageTarget.room, true ); StopNotVicious( victim ); break; case Position.stunned: victim.SendText( "&+LYou are stunned, but will probably recover.&n\r\n" ); SocketConnection.Act( "$n&+L is stunned, but will probably recover.&n", victim, null, null, SocketConnection.MessageTarget.room, true ); break; case Position.dead: SocketConnection.Act( spell.MessageKill, ch, null, victim, SocketConnection.MessageTarget.room_vict ); SocketConnection.Act( spell.MessageKill, ch, null, victim, SocketConnection.MessageTarget.character ); if( victim == ch ) { victim.SendText( "&+LYou have been &+Rsl&n&+ra&+Ri&n&+rn&+L!&n\r\n\r\n" ); } else { string buf = String.Format( "&+LYou have been &+Rsl&n&+ra&+Ri&n&+rn&+L by&n {0}&+L!&n\r\n\r\n", ch.ShowNameTo( victim, false ) ); victim.SendText( buf ); } StopFighting( victim, true ); SocketConnection.Act( "$n&+L is &n&+rdead&+L!&n", victim, null, null, SocketConnection.MessageTarget.room, true ); break; default: if( dam > victim.GetMaxHit() / 5 ) victim.SendText( "That really did &+RHURT&n!\r\n" ); if( victim.Hitpoints < victim.GetMaxHit() / 10 ) victim.SendText( "You sure are &n&+rBL&+RE&n&+rE&+RDI&n&+rN&+RG&n!\r\n" ); break; } /* * Sleep spells and extremely wounded folks. */ if( !victim.IsAwake() ) /* lets make NPC's not slaughter PC's */ { if( victim.Fighting && victim.Fighting.Hunting && victim.Fighting.Hunting.Who == victim ) StopHunting( victim.Fighting ); if( victim.Fighting && !victim.IsNPC() && ch.IsNPC() ) StopFighting( victim, true ); else StopFighting( victim, false ); } /* * Payoff for killing things. */ if( victim.CurrentPosition == Position.dead ) { StopFighting( ch, false ); if( !victim.HasActionBit(MobTemplate.ACT_NOEXP ) || !victim.IsNPC() ) GroupExperienceGain( ch, victim ); if( !victim.IsNPC() ) { if( ch.IsNPC() ) { ( (PC)victim ).MobDeaths++; if( victim.IsGuild() ) { ( (PC)victim ).GuildMembership.MonsterDeaths++; ( (PC)victim ).GuildMembership.Score += CalculateDeathScore( ch, victim ); } ( (PC)victim ).Score += CalculateDeathScore( ch, victim ); } else { ( (PC)ch ).PlayerKills++; ( (PC)victim ).PlayerDeaths++; ( (PC)victim ).Score += CalculateDeathScore( ch, victim ); ( (PC)ch ).Score += CalculateKillScore( ch, victim ); if( ch.IsGuild() && victim.IsGuild() && ( (PC)ch ).GuildMembership != ( (PC)victim ).GuildMembership ) { ( (PC)ch ).GuildMembership.PlayerKills++; ( (PC)victim ).GuildMembership.PlayerDeaths++; ( (PC)ch ).GuildMembership.Score += CalculateKillScore( ch, victim ); ( (PC)victim ).GuildMembership.Score += CalculateDeathScore( ch, victim ); } } string logBuf = String.Format( "{0}&n killed by {1}&n at {2}", victim.Name, ( ch.IsNPC() ? ch.ShortDescription : ch.Name ), victim.InRoom.IndexNumber ); Log.Trace( logBuf ); ImmortalChat.SendImmortalChat( ch, ImmortalChat.IMMTALK_DEATHS, Limits.LEVEL_AVATAR, logBuf ); /* * Dying penalty: * 1/2 way back to previous 2 levels. */ // Newbies do not lose exp from death. if( ch.Level > 5 ) victim.GainExperience( ( 0 - ( ( ( 50 + victim.Level ) * ExperienceTable.Table[ victim.Level ].LevelExperience ) / 400 ) ) ); if( victim.Level < 2 && victim.ExperiencePoints < 1 ) victim.ExperiencePoints = 1; } else { if( !ch.IsNPC() ) { ( (PC)ch ).MobKills++; if( ch.IsGuild() ) { ( (PC)ch ).GuildMembership.MonsterKills++; ( (PC)ch ).GuildMembership.Score += CalculateKillScore( ch, victim ); } ( (PC)ch ).Score += CalculateKillScore( ch, victim ); } } KillingBlow( ch, victim ); // Keep in mind after this point the character is not in the // CharList, not in any room, and is at the menu. Don't do // anything that would cause a segmentation fault. if( ch.IsGuild() && victim.IsGuild() && ( (PC)ch ).GuildMembership != ( (PC)victim ).GuildMembership ) { ( (PC)ch ).GuildMembership.Score += 20; } return true; } if( victim == ch ) { return false; } /* * Wimp out? */ if( victim.IsNPC() && dam > 0 ) { if( ( victim.HasActionBit(MobTemplate.ACT_WIMPY ) && MUDMath.NumberBits( 1 ) == 0 && victim.Hitpoints < victim.GetMaxHit() / 5 ) || (victim.IsAffected(Affect.AFFECT_CHARM) && victim.Master && victim.Master.InRoom != victim.InRoom ) ) { StartFearing( victim, ch ); StopHunting( victim ); CommandType.Interpret(victim, "flee"); } } if( !victim.IsNPC() && victim.Hitpoints > 0 && victim.Hitpoints <= victim.Wimpy ) { CommandType.Interpret(victim, "flee"); } return false; }
/// <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; }
/// <summary> /// Creating a portal. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <param name="indexNumber"></param> public static void MakePortal(CharData ch, Spell spell, int level, Target target, int indexNumber) { Room location; CharData victim = (CharData)target; Room original = ch.InRoom; if (ch.IsNPC()) return; if (!victim) { ch.SendText("Who exactly is your target?\r\n"); return; } if (victim.IsNPC() && !ch.IsImmortal()) return; if (!Magic.HasSpellConsent(ch, victim)) { return; } if (victim == ch || ch.InRoom == victim.InRoom) { ch.SendText("Seems like a waste of time.\r\n"); return; } if (!(location = victim.InRoom) || victim.InRoom.HasFlag(RoomTemplate.ROOM_SAFE) || victim.InRoom.HasFlag(RoomTemplate.ROOM_PRIVATE) || victim.InRoom.HasFlag(RoomTemplate.ROOM_SOLITARY)) { ch.SendText("You can't seem to get a fix their location.\r\n"); return; } if (!victim.IsNPC() && (ch.IsRacewar(victim)) && !ch.IsImmortal()) { ch.SendText("Don't you wish it was that easy!\r\n"); return; } Object portal = Database.CreateObject(Database.GetObjTemplate(indexNumber), 0); if (victim.InRoom.HasFlag(RoomTemplate.ROOM_NO_GATE) || ch.InRoom.HasFlag(RoomTemplate.ROOM_NO_GATE)) { SocketConnection.Act("$p opens for a brief instant and then collapses.&n", ch, portal, null, SocketConnection.MessageTarget.character); SocketConnection.Act("$p opens for a brief instant and then collapses.&n", ch, portal, null, SocketConnection.MessageTarget.room); SocketConnection.Act("$p opens for a brief instant and then collapses.&n", victim, portal, null, SocketConnection.MessageTarget.character); SocketConnection.Act("$p opens for a brief instant and then collapses.&n", victim, portal, null, SocketConnection.MessageTarget.room); portal.RemoveFromWorld(); return; } portal.Timer = level / 15; portal.Values[2] = level / 7; portal.Values[0] = location.IndexNumber; portal.AddToRoom(original); portal = Database.CreateObject(Database.GetObjTemplate(indexNumber), 0); portal.Timer = level / 15; portal.Values[2] = level / 7; portal.Values[0] = original.IndexNumber; portal.AddToRoom(location); switch (indexNumber) { case StaticObjects.OBJECT_NUMBER_PORTAL: SocketConnection.Act("$p&+Y rises up from the ground.&n", ch, portal, null, SocketConnection.MessageTarget.room); SocketConnection.Act("$p&+Y rises up before you.&n", ch, portal, null, SocketConnection.MessageTarget.character); if (location.People.Count > 0) { SocketConnection.Act("$p&+Y rises up from the ground.&n", location.People[0], portal, null, SocketConnection.MessageTarget.room); SocketConnection.Act("$p&+Y rises up from the ground.&n", location.People[0], portal, null, SocketConnection.MessageTarget.character); } break; case StaticObjects.OBJECT_NUMBER_MOONWELL: SocketConnection.Act("&+WSilver mists swirl and form into a $p.&n", ch, portal, null, SocketConnection.MessageTarget.room); SocketConnection.Act("&+WSilver mists swirl and form into a $p.&n", ch, portal, null, SocketConnection.MessageTarget.character); if (location.People.Count > 0) { SocketConnection.Act("&+WSilver mists swirl and form into a $p.&n", location.People[0], portal, null, SocketConnection.MessageTarget.room); SocketConnection.Act("&+WSilver mists swirl and form into a $p.&n", location.People[0], portal, null, SocketConnection.MessageTarget.character); } break; case StaticObjects.OBJECT_NUMBER_WORMHOLE: SocketConnection.Act("$p&+L appears from a warping of space and time.&n", ch, portal, null, SocketConnection.MessageTarget.room); SocketConnection.Act("$p&+L appears from a warping of space and time.&n", ch, portal, null, SocketConnection.MessageTarget.character); if (location.People.Count > 0) { SocketConnection.Act("$p&+L appears from a warping of space and time.&n", location.People[0], portal, null, SocketConnection.MessageTarget.room); SocketConnection.Act("$p&+L appears from a warping of space and time.&n", location.People[0], portal, null, SocketConnection.MessageTarget.character); } break; } ch.WaitState(8); return; }
/// <summary> /// Song of obscrurement. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongObscurement( CharData ch, Spell spell, int level, Target target ) { Affect af = new Affect(); foreach( CharData victim in ch.InRoom.People ) { if( victim.IsAffected( Affect.AFFECT_MINOR_INVIS ) || victim.IsAffected( Affect.AFFECT_INVISIBLE ) ) return true; SocketConnection.Act( "$n&n fades out of existence.", ch, null, null, SocketConnection.MessageTarget.room ); ch.SendText( "You vanish.\r\n" ); af.Type = Affect.AffectType.song; af.Value = spell.Name; af.Duration = level / 6; af.SetBitvector( Affect.AFFECT_MINOR_INVIS ); victim.AddAffect(af); } return true; }
/// <summary> /// Song of flight. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongFlight( CharData ch, Spell spell, int level, Target target ) { foreach( CharData victim in ch.InRoom.People ) { if (victim.IsAffected(Affect.AFFECT_FLYING)) return true; Affect af = new Affect(Affect.AffectType.song, spell.Name, (level / 6), Affect.Apply.none, 0, Affect.AFFECT_FLYING); victim.AddAffect(af); victim.SendText( "&+WYour feet rise off the ground.&n\r\n" ); SocketConnection.Act( "$n&n rises off the ground.", victim, null, null, SocketConnection.MessageTarget.room ); } return true; }
/// <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; }
public void ImprintSpell(Spell spell, int level, Target target) { int[] sucessRate = new[] { 80, 30, 25, 10 }; string text; Object obj = (Object)target; int freeSlots; int i; if (spell == null) { SendText("That is not a spell.\r\n"); return; } for (freeSlots = i = 1; i < 5; i++) if (obj.Values[i] != -1) freeSlots++; if (freeSlots > 4) { SocketConnection.Act("$p&n cannot contain any more spells.", this, obj, null, SocketConnection.MessageTarget.character); return; } int mana = 4 * Macros.ManaCost(this, spell); if (!IsNPC() && CurrentMana < mana) { SendText("You don't have enough mana.\r\n"); return; } if (MUDMath.NumberPercent() > ((PC)this).SpellAptitude[spell.Name] && (Level <= (spell.SpellCircle[(int)this.CharacterClass.ClassNumber] * 4 + 1))) { SendText("You lost your concentration.\r\n"); SocketConnection.Act("&+r$n&n&+r stops chanting abruptly.&n", this, null, null, SocketConnection.MessageTarget.room); CurrentMana -= mana / 2; return; } CurrentMana -= mana; // TODO: FIXME: BUG: Can't cram a string into a integer value inside an object. // This is a problem because it makes it impossible for objects to contain spells. //obj._values[free_slots] = spell; if (MUDMath.NumberPercent() > sucessRate[freeSlots - 1]) { text = String.Format("The magic enchantment has failed: the {0} vanishes.\r\n", StringConversion.ItemTypeString(obj)); SendText(text); obj.RemoveFromWorld(); ; return; } obj.ShortDescription = String.Empty; text = String.Format("a {0} of ", StringConversion.ItemTypeString(obj)); for (i = 1; i <= freeSlots; i++) { if (obj.Values[i] != -1) { text += SpellNumberToTextMap.GetSpellNameFromNumber(obj.Values[i]); if (i != freeSlots) { text += ", "; } else { text += String.Empty; } } } obj.ShortDescription = text; text = String.Format("{0} {1}", obj.Name, StringConversion.ItemTypeString(obj)); obj.Name = text; text = String.Format("You have imbued a new spell to the {0}.\r\n", StringConversion.ItemTypeString(obj)); SendText(text); return; }
/// <summary> /// Song of sleep. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongSleep( CharData ch, Spell spell, int level, Target target ) { foreach( CharData victim in ch.InRoom.People ) { if (victim.IsAffected(Affect.AFFECT_SLEEP) || Magic.SpellSavingThrow( level, victim, AttackType.DamageType.charm ) || victim.GetRace() == Race.RACE_VAMPIRE || ch.IsSameGroup( victim ) ) { continue; } Affect af = new Affect(Affect.AffectType.song, spell.Name, level / 8, Affect.Apply.none, 0, Affect.AFFECT_SLEEP); victim.CombineAffect(af); if( victim.IsAwake() ) { victim.SendText( "You feel very sleepy... zzzzz.\r\n" ); if (ch.Fighting || victim.CurrentPosition == Position.fighting) { Combat.StopFighting(victim, false); } CommandType.Interpret( victim, "sleep" ); } } return true; }
/// <summary> /// Forwards to the string-based HasAffect. If checking whether a character is /// affected by a specific type of affect rather than an exact spell, use /// CharData.IsAffected() instead. /// </summary> /// <param name="type"></param> /// <param name="value"></param> /// <returns></returns> public bool HasAffect(Affect.AffectType type, Spell value) { return HasAffect(type, value.Name); }
public bool HasSpell(Spell Spell) { if (!HasLevelForSpell(Spell)) { return false; } else if (IsNPC()) { return true; } if (!((PC)this).SpellAptitude.ContainsKey(Spell.Name)) { return false; } if (((PC)this).SpellAptitude[Spell.Name] < 1) { return false; } return true; }
/// <summary> /// Song of heroism. /// </summary> /// <param name="ch"></param> /// <param name="spell"></param> /// <param name="level"></param> /// <param name="target"></param> /// <returns></returns> public static bool SongHeroism( CharData ch, Spell spell, int level, Target target ) { foreach( CharData victim in ch.InRoom.People ) { Affect af = new Affect(Affect.AffectType.song, spell.Name, (level / 8), Affect.Apply.hitroll, (level / 6 + 1), Affect.AFFECT_NONE); victim.AddAffect(af); af = new Affect(Affect.AffectType.song, spell.Name, (level / 8), Affect.Apply.damroll, (level / 11 + 1), Affect.AFFECT_NONE); victim.AddAffect(af); SocketConnection.Act( "$n&n looks more courageous.", victim, null, null, SocketConnection.MessageTarget.room ); victim.SendText( "You feel righteous.\r\n" ); } 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> /// Checks whether the skill level of the specified spell should increase (due to use). /// </summary> /// <param name="spell"></param> public void PracticeSpell( Spell spell ) { if( IsNPC() || !((PC)this).SpellAptitude.ContainsKey(spell.Name) ) { return; } // Have to be below the max and below 95% and make a successful // spell check and be able to have the spell. if (((PC)this).SpellAptitude[spell.Name] < Limits.MAX_SPELL_ADEPT && MUDMath.NumberRange(1, 1000) <= (10 + (GetCurrInt() / 5))) { ((PC)this).SpellAptitude[spell.Name] = ((PC)this).SpellAptitude[spell.Name] + 1; SendText( "&+cYe feel yer knowledge of " + spell.Name + " improving.&n\r\n" ); } return; }
/// <summary> /// Check for use of Direct targeted spells (TargetType.singleCharacterOffensive) /// </summary> /// <param name="ch"></param> /// <param name="victim"></param> /// <param name="spell"></param> /// <param name="percent"></param> /// <returns></returns> public static bool CheckOffensive( CharData ch, CharData victim, Spell spell, int percent ) { if (ch == null) return false; string buf = String.Format("CheckOffensive: spell ({0})'{1}'", spell, spell.Name); Log.Trace( buf ); if( spell == null ) return false; if( ch.HasSpell(spell) && ( MUDMath.NumberPercent() < percent ) ) { if (spell.ValidTargets != TargetType.singleCharacterOffensive && spell.ValidTargets != TargetType.none && spell.ValidTargets != TargetType.singleCharacterRanged) Log.Error( "Check_spellup: Mob casting spell {0} which is neither _targetType offensive nor ignore.a", spell ); SocketConnection.Act( "$n&n starts casting...", ch, null, null, SocketConnection.MessageTarget.room ); ch.SetAffectBit( Affect.AFFECT_CASTING ); CastData caster = new CastData(); caster.Who = ch; caster.Eventdata = Event.CreateEvent(Event.EventType.spell_cast, spell.CastingTime, ch, victim, spell); Database.CastList.Add( caster ); return true; } return false; }
/// <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; }