/// <summary> /// Adds a creature to a single tile with only the /// most basic information. Note: Used for speeding up /// loading spawns. /// </summary> /// <param name="creature">Creature to add.</param> /// <param name="position">Position to add creature.</param> public void AddCachedCreature(Creature creature, Position position) { lock (lockThis) { creature.World = this; creaturesOnline.Add(creature.GetID(), creature); creature.Finder = pathFinder; creature.LogedIn = true; gameMap.AddThing(creature, position); } }
/// <summary> /// Handle a message from a creature. /// </summary> /// <param name="creature">The creature sending the message.</param> /// <param name="msg">The message sent.</param> public void HandleChat(Creature creature, string msg) { ThingSet tSet = new ThingSet(); if (msg.StartsWith(PRIVATE_MSG_INDICATOR)) { HandlePrivateMessage(creature, msg); } else if (msg.StartsWith(MSG_QUANTIFIER)) { HandleQuantifiedMessage(creature, msg, tSet); } else { tSet = gameMap.GetThingsInVicinity(creature.CurrentPosition, true); HandleLocalChat(creature.GetChatType(), tSet, msg, creature); } }
public override bool HandleWalkAction(Creature creature, GameWorld world, WalkType type) { if (walkItems.ContainsKey(this.ItemID)) { return walkItems[ItemID](this, creature, world, type); } return true; }
/// <summary> /// Lets the creature know that it was damaged by another creature. /// Note: This method adjusts the damage as needed if hp less than 0 or /// greater than max. /// </summary> /// <param name="dmgAmt">Damage amt to add.</param> /// <param name="attacker">The name of the attacker, null if none.</param> /// <param name="magic">True if it was a magic attack, false otherwise.</param> public virtual void AddDamage(int dmgAmt, Creature attacker, bool magic) { if (CurrentHP - dmgAmt < 0) { dmgAmt = CurrentHP; } else if (CurrentHP - dmgAmt > MaxHP) { dmgAmt = -1 * (MaxHP - CurrentHP); } CurrentHP = (ushort)(CurrentHP - dmgAmt); if (dmgAmt > 0) { string loseString = "You lose " + dmgAmt + " hitpoint" + (dmgAmt > 1 ? "s" : "") + "."; string leftString = " You have " + CurrentHP + " hitpoint" + (CurrentHP > 1 ? "s" : "") + " left."; AddStatusMessage(loseString + leftString); } if (CurrentHP == 0) { CurrentHealthStatus = HealthStatus.DEAD; } else { //THE FORMULA! Lolz int divisor = MaxHP / 5; CurrentHealthStatus = (HealthStatus)((CurrentHP / divisor) + 1); if (CurrentHealthStatus >= HealthStatus.TOTAL_TYPES) { throw new Exception("Invalid health status in AddDamage()"); } } }
public bool GetPathTo(Creature creature, Position destPos, List<byte> listDir, Int32 maxSearchDist, bool allowZChange, bool intendingToReachDes) { if (intendingToReachDes && gameMap.TileContainsType(destPos, Constants.TYPE_BLOCKS_AUTO_WALK)) { listDir.Clear(); return false; } listDir.Clear(); Position startPos = creature.CurrentPosition; Position endPos = destPos; if (endPos == null) { return false; } if (startPos.z != endPos.z) return false; AStarNodes nodes = new AStarNodes(); AStarNode startNode = nodes.CreateOpenNode(); startNode.x = startPos.x; startNode.y = startPos.y; startNode.g = 0; startNode.h = nodes.GetEstimatedDistance (startPos.x, startPos.y, endPos.x, endPos.y); startNode.f = startNode.g + startNode.h; startNode.parent = null; Position pos = new Position(); pos.z = startPos.z; short[,] neighbourOrderList = { {-1, 0}, {0, 1}, {1, 0}, {0, -1}, //diagonal {-1, -1}, {1, -1}, {1, 1}, {-1, 1}, }; //MapTile tile = null; AStarNode found = null; while (nodes.CountClosedNodes() < 100) { AStarNode n = nodes.GetBestNode(); if (n == null) { listDir.Clear(); return false; //No path found } if (n.x == endPos.x && n.y == endPos.y) { found = n; break; } else { for (int i = 0; i < 8; i++) { if (i > 3 && (allowZChange || intendingToReachDes)) { continue; } //Console.WriteLine("neighbourhood["+i+", 1]" + neighbourOrderList[i, 0]); pos.x = (ushort)(n.x + neighbourOrderList[i, 0]); pos.y = (ushort)(n.y + neighbourOrderList[i, 1]); int endPosX = endPos.x; int endPosY = endPos.y; int posX = pos.x; int posY = pos.y; bool outOfRange = false; if (Math.Abs(endPosX - posX) > maxSearchDist || Math.Abs(endPosY - posY) > maxSearchDist) { outOfRange = true; } if ((!outOfRange) && (!gameMap.TileContainsType(pos, Constants.TYPE_BLOCKS_AUTO_WALK)) || (destPos.x == pos.x && destPos.y == pos.y)) { if (i > 3 && !destPos.Equals(pos)) { nodes.CloseNode(n); continue; } int cost = 0; int extraCost = 0; int newg = n.g + cost + extraCost; AStarNode neighbourNode = nodes.GetNodeInList(pos.x, pos.y); if (neighbourNode != null) { if (neighbourNode.g <= newg) { continue; } nodes.OpenNode(neighbourNode); } else { neighbourNode = nodes.CreateOpenNode(); if (neighbourNode == null) { listDir.Clear(); return false; } } neighbourNode.x = pos.x; neighbourNode.y = pos.y; neighbourNode.parent = n; neighbourNode.g = newg; neighbourNode.h = (nodes.GetEstimatedDistance((int)neighbourNode.x, (int)neighbourNode.y, (int)endPos.x, (int)endPos.y)); neighbourNode.f = neighbourNode.g + neighbourNode.h; } } nodes.CloseNode(n); } } int prevX = endPos.x; int prevY = endPos.y; int dx, dy; while (found != null) { pos.x = (ushort)found.x; pos.y = (ushort)found.y; found = found.parent; dx = pos.x - prevX; dy = pos.y - prevY; prevX = pos.x; prevY = pos.y; if (dx == 1) listDir.Insert(0, (byte)Direction.WEST); else if (dx == -1) listDir.Insert(0, (byte)Direction.EAST); else if (dy == 1) listDir.Insert(0, (byte)Direction.NORTH); else if (dy == -1) listDir.Insert(0, (byte)Direction.SOUTH); } bool empty = true; if (listDir.Count == 0) empty = false; return (!empty); }
public virtual void AppendNotifyOfDeath(Item corpse, Map gameMap) { if (CurrentHP == 0) { CreatureAttacking = null; } }
public void SetIdle() { talkingTo = null; }
/// <summary> /// Handles sending a chat message in a player's local vicinity. /// </summary> /// <param name="type">The type of chat to send.</param> /// <param name="set">The set of things in the player's local vicinity.</param> /// <param name="msg">The message to send.</param> /// <param name="sender">The sender of the message.</param> private void HandleLocalChat(ChatLocal type, ThingSet set, string msg, Creature sender) { foreach (Thing thing in set.GetThings()) { thing.AddLocalChat(type, msg, sender.CurrentPosition, sender); } }
/// <summary> /// A quantified message is a message that starts with a special character. For example, /// in tibia 6.4, # is a quantifier, so #y is used to yell, #w is used to whisper etc. /// </summary> /// <param name="sender">Sender of the quantified message.</param> /// <param name="msg">The message itself.</param> private void HandleQuantifiedMessage(Creature sender, string msg, ThingSet tSet) { if (!msg.StartsWith(MSG_QUANTIFIER)) { throw new Exception("Invalid call to HandleQuantifiedMessage()"); } msg = msg.Substring(1); //Remove first quanitifer char quantifierType = char.ToLower(msg[0]); switch (quantifierType) { case BROADCAST_TYPE: HandleBroadcast(sender, msg); break; case WHISPER_TYPE: gameMap.GetThingsInWhisperVicinity(sender.CurrentPosition, tSet); //msg.Substring(2) is called in order to remove quantifier type and a space HandleLocalChat(ChatLocal.WHISPER, tSet, msg.Substring(2), sender); break; case YELL_TYPE: gameMap.GetThingsInYellVacinity(sender.CurrentPosition, tSet); //msg.Substring(2) is called in order to remove quantifier type and a space HandleLocalChat(ChatLocal.YELLS, tSet, msg.Substring(2).ToUpper(), sender); break; default: #if DEBUG Log.WriteDebug("Invalid quantifier type"); #endif break; } }
public override void AddDamage(int dmgAmt, Creature attacker, bool magic) { base.AddDamage(dmgAmt, attacker, magic); totalDamageDealt += dmgAmt; if (attacker == null) { return; } foreach (AttackersInformation info in attackersInfoList) { if (info.Attacker == attacker) { info.DamageByCreature += dmgAmt; return; } } //Attacker not found in list... therefore add attacker attackersInfoList.Add(new AttackersInformation(attacker, dmgAmt)); }
public override void AddTileCreature(Creature creature, Position position, byte stackpos) { if (!creature.AttackableByMonster()) { return; } potentialTargets.Add(creature); }
/// <summary> /// Gets a position for which a creature could be added. /// Returns null if all the spaces around this position are taken. /// </summary> /// <param name="curPos">The position to add the creature.</param> /// <param name="creatureFor">The creature to add.</param> /// <returns>A free space or null if all spaces are taken.</returns> public Position GetFreePosition(Position curPos, Creature creatureFor) { Position tempPos = curPos.Clone(); if (!TileContainsType(curPos, Constants.TYPE_BLOCKS_AUTO_WALK)) { return tempPos; } for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { tempPos.x = (ushort)(curPos.x + i); tempPos.y = (ushort)(curPos.y + j); if (!TileContainsType(tempPos, Constants.TYPE_BLOCKS_AUTO_WALK)) { return tempPos; } } } return null; }
public override void AddCreatureMove(Direction direction, Creature creature, Position oldPos, Position newPos, byte oldStackpos, byte newStackpos) { if (!creature.AttackableByMonster()) { return; } potentialTargets.Add(creature); PerformThink(); }
public void TurnTowardsTarget(Creature target) { //basic error checks if (target == null) return; //Here comes the formula :D Position oppPos = target.CurrentPosition; Position thisPos = this.CurrentPosition; Direction directionToTurn = Direction.WEST; if (oppPos.x < thisPos.x) { directionToTurn = Direction.WEST; } else if (oppPos.x > thisPos.x) { directionToTurn = Direction.EAST; } else if (oppPos.y < thisPos.y) { directionToTurn = Direction.NORTH; } else if (oppPos.y > thisPos.y) { directionToTurn = Direction.SOUTH; } if (CurrentDirection == directionToTurn) { //Already facing this direction... return; } World.HandleChangeDirection(this, directionToTurn); }
public void SetCreatureAttacking(Creature creature) { foreach (Monster summon in summons) { summon.SetCreatureAttacking(creature); } CreatureAttacking = creature; }
/// <summary> /// Gets how much damage to be done to this creature based on /// the attacking creature's stats. /// </summary> /// <param name="attacker">The creature attacking.</param> /// <returns>The damage amount if > 0 or PUFF/SPARK constants /// otherwise.</returns> public int GetDamageAmt(Creature attacker) { int atkValue = attacker.GetAtkValue(); int shieldValue = this.GetShieldValue(); int netValue = atkValue - shieldValue; if (netValue > 0) { return netValue; } else if (netValue == 0) { return Constants.SPARK; } else { return Constants.PUFF; } }
public void HandlePush(Player player, Position posFrom, ushort thingID, byte stackpos, Position posTo, byte count, Creature creatureMoved) { HandlePush(player, posFrom, thingID, stackpos, posTo, count); creatureToMove = creatureMoved; if (!creatureMoved.IsOfType(Constants.TYPE_MOVEABLE) || map.GetTile(posTo) == null) { return; } if (map.GetTile(posTo).ContainsType(Constants.TYPE_BLOCKS_AUTO_WALK) || !creatureToMove.IsNextTo(posTo) || !player.IsNextTo(posFrom)) { return; } world.HandleMove(creatureMoved, posTo, creatureToMove.CurrentDirection); }
public AttackersInformation(Creature atker, int amtDealt) { Attacker = atker; DamageByCreature = amtDealt; }
/// <summary> /// Handles a broadcast made by a creature. /// </summary> /// <param name="sender">The sender of the broadcast.</param> /// <param name="msg">The message to broadcast.</param> private void HandleBroadcast(Creature sender, string msg) { if (!msg.ToLower().StartsWith(BROADCAST_TYPE + "")) { throw new Exception("Invalid call to HandleBroadcast()"); } msg = msg.Substring(1); //Remove quantifier type //Invalid access level if (sender.Access < Constants.ACCESS_GAMEMASTER) { return; } foreach (KeyValuePair<string, Player> kvp in playersOnline) { kvp.Value.ResetNetMessages(); kvp.Value.AddGlobalChat(ChatGlobal.BROADCAST, msg, sender.Name); kvp.Value.WriteToSocket(); } }
/// <summary> /// Sends a private message to another player. /// </summary> /// <param name="sender">The creature sending.</param> /// <param name="recipient">The recipient's name (player).</param> /// <param name="msg">The message to send.</param> private void AppendPrivateMessage(Creature sender, string recipient, string msg) { recipient = recipient.ToLower(); foreach (KeyValuePair<string, Player> kvp in playersOnline) { if (kvp.Key.StartsWith(recipient)) { kvp.Value.AddGlobalChat(ChatGlobal.PRIVATE_MSG, msg, sender.Name); sender.AddStatusMessage("Message sent to " + kvp.Value.Name + "."); return; } } sender.AddStatusMessage("A player with this name is not online."); }
/// <summary> /// This method handles a private message. /// </summary> /// <param name="sender">The sender of the message.</param> /// <param name="msg">The message itself.</param> private void HandlePrivateMessage(Creature sender, string msg) { // Valid format: *name* msg if (!msg.StartsWith(PRIVATE_MSG_INDICATOR)) { throw new Exception("Invalid call to HandlePrivateMessage()"); } bool isName = true; string name = ""; string message = ""; for (int i = 1; i < msg.Length; i++) { string charAt = msg[i] + ""; if (charAt == PRIVATE_MSG_INDICATOR) { isName = false; continue; //Skip adding PRIVATE_MSG_INDICATOR to message } if (isName) { name += charAt; } else { message += charAt; } } //Remove starting space, if applicable; if (message.StartsWith(EMPTY_SPACE)) { #if DEBUG Log.WriteDebug("Message started with empty space."); #endif message = message.Substring(1); } AppendPrivateMessage(sender, name, message); }
public static Spell CreateCreatureSpell(string name, string argument, Creature creature, int min, int max, Position spellCenter) { Spell spell = new Spell(); otherSpells[name.ToLower()].InitDelegate.Invoke (new object[] { name, creature, min, max, spellCenter, spell, argument }); return spell; }
/// <summary> /// Set the master for this monster thus making it /// a summoned/convinced creature. To make this monster wild (again), /// send null as the argument. /// </summary> /// <param name="creature">Creature to set as the master.</param> public void SetMaster(Creature creature) { if (creature != null) { creature.AddSummon(this); } Master = creature; }
public override void AppendHandleDamage(int dmgAmt, Creature attacker, ImmunityType type, GameWorld world, bool magic) { world.AppendAddDamage(attacker, this, dmgAmt, type, magic); }
/// <summary> /// Use this method cast the specified spell. Note: This method only /// appends and does not send protocol data. /// </summary> /// <param name="caster">The creature casting the spell</param> /// <param name="spell">The spell to cast</param> /// <param name="tSet">The set of affected things</param> public void CastSpell(string msg, Creature caster, Spell spell, GameWorld world) { /*string error = caster.CanCastSpell(spell); if (error != null) { caster.AddAnonymousChat(ChatAnonymous.WHITE, error); return; }*/ //TODO: Uncomment if (spell.IsSpellValid != null && !spell.IsSpellValid(world, msg)) { world.AddMagicEffect(MagicEffect.PUFF, caster.CurrentPosition); return; } if (spell.RequiresTarget) { Tile tile = map.GetTile(spell.SpellCenter); if (tile == null || !tile.ContainsType(Constants.TYPE_CREATURE)) { world.AddMagicEffect(MagicEffect.PUFF, caster.CurrentPosition); caster.AddAnonymousChat(ChatAnonymous.WHITE, "No target selected."); return; } } //Constants. //Not the most efficient method but it is simple and works. int length = spell.SpellArea.GetLength(0); int width = spell.SpellArea.GetLength(1); Position startPos = new Position(); startPos.x = (ushort)(spell.SpellCenter.x - (width / 2)); startPos.y = (ushort)(spell.SpellCenter.y - (length / 2)); startPos.z = spell.SpellCenter.z; Position local = new Position(); List<Thing> things = new List<Thing>(); for (int i = 0; i < length; i++) { for (int j = 0; j < width; j++) { local.x = (ushort)(startPos.x + j); local.y = (ushort)(startPos.y + i); local.z = startPos.z; if (map.GetTile(local) == null /*|| !map.GetTile(local).CanMoveTo(caster) * TODO: Finish*/) { continue; } if (spell.SpellArea[i, j] && !map.GetTile(local).ContainsType(Constants.TYPE_BLOCKS_MAGIC)) { ThingSet tSet = map.GetThingsInVicinity(local); foreach (Thing thing in tSet.GetThings()) { thing.AddEffect(spell.SpellEffect, local); if (spell.HasDistanceType()) { thing.AddShootEffect((byte)spell.DistanceEffect, caster.CurrentPosition, spell.SpellCenter); } } List<Thing> localThings = map.GetTile(local).GetThings(); if (spell.Action != null) { spell.Action.Invoke(world, local, localThings); } foreach (Thing thing in map.GetTile(local).GetThings()) { things.Add(thing); } } } } foreach (Thing thing in things) { thing.AppendHandleDamage(spell.GetDamage(), caster, spell.Immunity, world, true); } //caster.NotifyOfSuccessfulCast(spell); TODO: Uncomment }
private bool ExistsPath(Creature creature) { List<byte> dir = new List<byte>(); Finder.GetPathTo(this, creature.CurrentPosition, dir, 12, false, false); return dir.Count > 0; }
public override void AddLocalChat(ChatLocal chatType, string message, Position pos, Creature creatureFrom) { if (creatureFrom == this) { return; } lastMessage = message.ToLower(); lastMessage = lastMessage.Replace(".", ""); lastMessage = lastMessage.Replace("?", ""); lastCreatureSay = creatureFrom; HandleMessage(); }
public bool GetPathTo(Creature creature, Position destPos, ref List<byte> listDir, Int32 maxSearchDist) { return GetPathTo(creature, destPos, listDir, 12, false); }
public void SetTalkingTo() { talkingTo = lastCreatureSay; }
public bool GetPathTo(Creature creature, Position destPos, List<byte> listDir, Int32 maxSearchDist, bool allowZChange) { return GetPathTo(creature, destPos, listDir, maxSearchDist, allowZChange, false); }