Not all options are used in all props. Things like ExtraData, State, etc. are all very prop specific.
Inheritance: Entity
Esempio n. 1
0
		/// <summary>
		/// Broadcasts PropDisappears in prop's region.
		/// </summary>
		/// <param name="prop"></param>
		public static void PropDisappears(Prop prop)
		{
			var packet = new Packet(Op.PropDisappears, MabiId.Broadcast);
			packet.PutLong(prop.EntityId);

			prop.Region.Broadcast(packet, prop, false);
		}
Esempio n. 2
0
		/// <summary>
		/// Broadcasts prop update in its region.
		/// </summary>
		/// <param name="prop"></param>
		public static void PropUpdate(Prop prop)
		{
			var packet = new Packet(Op.PropUpdate, prop.EntityId);
			packet.AddPropUpdateInfo(prop);

			prop.Region.Broadcast(packet);
		}
Esempio n. 3
0
        /// <summary>
        /// Sends BlacksmithingMiniGame to creature's client, which starts
        /// the Blacksmithing mini-game.
        /// </summary>
        /// <remarks>
        /// The position of the dots is relative to the upper left of the
        /// field. They land exactly on those spots after "wavering" for a
        /// moment. This wavering is randomized on the client side and
        /// doesn't affect anything.
        /// 
        /// The time bar is always the same, but the time it takes to fill
        /// up changes based on the "time displacement". The lower the value,
        /// the longer it takes to fill up. Using values that are too high
        /// or too low mess up the calculations and cause confusing results.
        /// The official range seems to be between ~0.81 and ~0.98.
        /// </remarks>
        /// <param name="creature"></param>
        /// <param name="prop"></param>
        /// <param name="item"></param>
        /// <param name="dots"></param>
        /// <param name="deviation"></param>
        public static void BlacksmithingMiniGame(Creature creature, Prop prop, Item item, List<BlacksmithDot> dots, int deviation)
        {
            if (dots == null || dots.Count != 5)
                throw new ArgumentException("5 dots required.");

            var packet = new Packet(Op.BlacksmithingMiniGame, creature.EntityId);

            // Untested if this is actually the deviation/cursor size,
            // but Tailoring does something very similar. Just like with
            // Tailoring, wrong values cause failed games.
            packet.PutShort((short)deviation);

            foreach (var dot in dots)
            {
                packet.PutShort((short)dot.X);
                packet.PutShort((short)dot.Y);
                packet.PutFloat(dot.TimeDisplacement);
                packet.PutShort((short)dot.Deviation);
            }

            packet.PutLong(prop.EntityId);
            packet.PutInt(0);
            packet.PutLong(item.EntityId);
            packet.PutInt(0);

            creature.Client.Send(packet);
        }
Esempio n. 4
0
File: Chest.cs Progetto: Vinna/aura
		protected virtual void DefaultBehavior(Creature creature, Prop prop)
		{
			if (this.State == "open")
				return;

			this.SetState("open");
			this.DropItems(creature);
		}
Esempio n. 5
0
		/// <summary>
		/// Door's behavior.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="prop"></param>
		private void DefaultBehavior(Creature creature, Prop prop)
		{
			// Open doors can't be interacted with
			if (this.State == "open")
				return;

			// If it's unlocked, warp inside
			if (!this.IsLocked)
			{
				this.WarpInside(creature, prop);
				return;
			}

			// Check if it's switch room door
			if (_isSwitchDoor)
				return;

			// Check dungeon doors for boss room doors
			// TODO: Mixing normal and boss doors like this seems wrong.
			if (this.DoorType == DungeonBlockType.BossDoor)
			{
				var dungeonRegion = this.Region as DungeonRegion;
				if (dungeonRegion != null)
				{
					// Check if all rooms have been cleared
					if (!dungeonRegion.Dungeon.CheckDoors())
					{
						Send.Notice(creature, Localization.Get("Unable to enter the boss room. There must be a closed door somewhere in the dungeon."));
						return;
					}
				}
			}

			// Check if character has the key
			if (!this.RemoveKey(creature))
			{
				Send.Notice(creature, NoticeType.MiddleSystem, Localization.Get("There is no matching key."));
				return;
			}

			// Unlock the door, but don't open it if it's supposed to block the bosses
			if (this.BlockBoss)
			{
				if (this.State != "unlocked")
				{
					this.SetState("unlocked");
					this.IsLocked = false;
					_closedFrom = new Position(_closedFrom.X, _closedFrom.Y + 1); // Fix closed from to be inside boss room.
					this.AddConfirmation();
				}
				this.WarpInside(creature, prop);
			}
			else
				this.Open();

			Send.Notice(creature, NoticeType.MiddleSystem, Localization.Get("You have opened the door with the key."));
		}
Esempio n. 6
0
		/// <summary>
		/// Broadcasts new prop extension.
		/// </summary>
		/// <param name="prop"></param>
		/// <param name="ext"></param>
		public static void AddPropExtension(Prop prop, PropExtension ext)
		{
			var packet = new Packet(Op.AddPropExtension, prop.EntityId);
			packet.PutInt((int)ext.SignalType);
			packet.PutInt((int)ext.EventType);
			packet.PutString(ext.Name);
			packet.PutByte(ext.Mode);
			packet.PutString(ext.Value.ToString());

			prop.Region.Broadcast(packet);
		}
Esempio n. 7
0
		public static Packet AddPropInfo(this Packet packet, Prop prop)
		{
			packet.PutLong(prop.EntityId);
			packet.PutInt(prop.Info.Id);

			// Client side props (A0 range, instead of A1)
			// look a bit different.
			if (prop.ServerSide)
			{
				packet.PutString(prop.Ident);
				packet.PutString(prop.Title);
				packet.PutBin(prop.Info);
				packet.PutString(prop.State);
				packet.PutLong(0);

				packet.PutByte(prop.HasXml);
				if (prop.HasXml)
					packet.PutString(prop.Xml.ToString());

				packet.PutInt(prop.Extensions.Count);
				foreach (var ext in prop.Extensions)
				{
					packet.PutInt((int)ext.SignalType);
					packet.PutInt((int)ext.EventType);
					packet.PutString(ext.Name);
					packet.PutByte(ext.Mode);
					packet.PutString(ext.Value.ToString());
				}

				packet.PutShort(0);
			}
			else
			{
				packet.PutString(prop.State);
				packet.PutLong(DateTime.Now);

				if (prop.HasXml)
				{
					packet.PutByte(true);
					packet.PutString(prop.Xml.ToString());
				}
				else
				{
					packet.PutByte(false);
				}

				packet.PutFloat(prop.Info.Direction);
			}

			return packet;
		}
Esempio n. 8
0
		/// <summary>
		/// Sends positive PersonalShopSetUpR to creature's client.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="shopProp"></param>
		public static void PersonalShopSetUpR(Creature creature, Prop shopProp)
		{
			var location = shopProp.GetLocation();

			var packet = new Packet(Op.PersonalShopSetUpR, creature.EntityId);
			packet.PutByte(true);
			packet.PutLong(shopProp.EntityId);
			packet.PutByte(1); // no location if 0?
			packet.PutInt(location.RegionId);
			packet.PutInt(location.X);
			packet.PutInt(location.Y);

			creature.Client.Send(packet);
		}
Esempio n. 9
0
		public static Packet AddPropUpdateInfo(this Packet packet, Prop prop)
		{
			packet.PutString(prop.State);
			packet.PutLong(DateTime.Now);

			packet.PutByte(prop.HasXml);
			if (prop.HasXml)
				packet.PutString(prop.Xml.ToString());

			packet.PutFloat(prop.Info.Direction);
			packet.PutShort(0);

			return packet;
		}
Esempio n. 10
0
		/// <summary>
		/// Fountain's default behavior, checking state, who and how many times
		/// they used the fountain, and calling Touch.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="prop"></param>
		protected virtual void DefaultBehavior(Creature creature, Prop prop)
		{
			if (!this.IsOn)
				return;

			lock (_touchedBy)
			{
				if (_touchedBy.Contains(creature.EntityId))
					return;
				_touchedBy.Add(creature.EntityId);
			}

			this.Touch(creature);

			Interlocked.Increment(ref count);
			if (count >= MaxTouch)
				this.TurnOff();
		}
Esempio n. 11
0
File: Door.cs Progetto: xKamuna/aura
		/// <summary>
		/// Door's behavior.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="prop"></param>
		private void DefaultBehavior(Creature creature, Prop prop)
		{
			// Open doors can't be interacted with
			if (this.State == "open")
				return;

			// If it's unlocked, warp inside
			if (!this.IsLocked)
			{
				this.WarpInside(creature, prop);
				return;
			}

			// Check if it's switch room door
			if (_isSwitchDoor)
				return;

			// Check if character has the key
			if (!this.RemoveKey(creature))
			{
				Send.Notice(creature, NoticeType.MiddleSystem, Localization.Get("There is no matching key."));
				return;
			}

			// Unlock the door, but don't open it if it's supposed to block the bosses
			if (this.BlockBoss)
			{
				if (this.State != "unlocked")
				{
					this.SetState("unlocked");
					this.IsLocked = false;
					_closedFrom = new Position(_closedFrom.X, _closedFrom.Y + 1); // Fix closed from to be inside boss room.
					this.AddConfirmation();
				}
				this.WarpInside(creature, prop);
			}
			else
				this.Open();

			Send.Notice(creature, NoticeType.MiddleSystem, Localization.Get("You have opened the door with the key."));
		}
Esempio n. 12
0
		/// <summary>
		/// Uses LightningRod
		/// </summary>
		/// <param name="attacker"></param>
		/// <param name="skill"></param>
		/// <param name="packet"></param>
		public void Use(Creature attacker, Skill skill, Packet packet)
		{
			// Set full charge variable
			attacker.Temp.LightningRodFullCharge = (DateTime.Now >= attacker.Temp.LightningRodPrepareTime.AddMilliseconds(skill.RankData.Var3));

			// Get direction for target Area
			var direction = Mabi.MabiMath.ByteToRadian(attacker.Direction);

			var attackerPos = attacker.GetPosition();

			// Calculate polygon points
			var r = MabiMath.ByteToRadian(attacker.Direction);
			var poe = attackerPos.GetRelative(r, 800);
			var pivot = new Point(poe.X, poe.Y);
			var p1 = new Point(pivot.X - SkillLength / 2, pivot.Y - SkillWidth / 2);
			var p2 = new Point(pivot.X - SkillLength / 2, pivot.Y + SkillWidth / 2);
			var p3 = new Point(pivot.X + SkillLength / 2, pivot.Y + SkillWidth / 2);
			var p4 = new Point(pivot.X + SkillLength / 2, pivot.Y - SkillWidth / 2);
			p1 = this.RotatePoint(p1, pivot, r);
			p2 = this.RotatePoint(p2, pivot, r);
			p3 = this.RotatePoint(p3, pivot, r);
			p4 = this.RotatePoint(p4, pivot, r);

			// TargetProp
			var lProp = new Prop(280, attacker.RegionId, poe.X, poe.Y, MabiMath.ByteToRadian(attacker.Direction), 1f, 0f, "single");
			attacker.Region.AddProp(lProp);

			// Prepare Combat Actions
			var cap = new CombatActionPack(attacker, skill.Info.Id);

			var targetAreaId = new Location(attacker.RegionId, poe).ToLocationId();

			var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetAreaId);
			aAction.Set(AttackerOptions.KnockBackHit1 | AttackerOptions.UseEffect);
			aAction.PropId = lProp.EntityId;
			cap.Add(aAction);

			// Get targets in Polygon - includes collission check
			var targets = attacker.Region.GetCreaturesInPolygon(p1, p2, p3, p4).Where(x => attacker.CanTarget(x) && !attacker.Region.Collisions.Any(attacker.GetPosition(), x.GetPosition())).ToList();

			var rnd = RandomProvider.Get();

			// Check crit
			var crit = false;
			var critSkill = attacker.Skills.Get(SkillId.CriticalHit);
			if (critSkill != null && critSkill.Info.Rank > SkillRank.Novice)
			{
				var critChance = Math2.Clamp(0, 30, attacker.GetTotalCritChance(0));
				if (rnd.NextDouble() * 100 < critChance)
					crit = true;
			}

			foreach (var target in targets)
			{
				var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, SkillId.CombatMastery);
				tAction.Set(TargetOptions.None);
				tAction.AttackerSkillId = skill.Info.Id;
				cap.Add(tAction);

				var damage = attacker.GetRndMagicDamage(skill, skill.RankData.Var1, skill.RankData.Var2);

				// Add damage if the skill is fully charged
				var dmgMultiplier = skill.RankData.Var4 / 100f;
				if (attacker.Temp.LightningRodFullCharge)
				{
					damage += (damage * dmgMultiplier);
				}

				// Critical Hit
				if (crit)
				{
					var bonus = critSkill.RankData.Var1 / 100f;
					damage = damage + (damage * bonus);

					tAction.Set(TargetOptions.Critical);
				}

				// MDef and MProt
				SkillHelper.HandleMagicDefenseProtection(target, ref damage);

				// Conditions
				SkillHelper.HandleConditions(attacker, target, ref damage);

				// Mana Deflector
				var delayReduction = ManaDeflector.Handle(attacker, target, ref damage, tAction);

				// Mana Shield
				ManaShield.Handle(target, ref damage, tAction);

				// Apply Damage
				target.TakeDamage(tAction.Damage = damage, attacker);

				// Stun Time
				tAction.Stun = TargetStun;

				// Death or Knockback
				if (target.IsDead)
				{
					tAction.Set(TargetOptions.FinishingKnockDown);
					attacker.Shove(target, KnockbackDistance);
				}
				else
				{
					// Always knock down
					if (target.Is(RaceStands.KnockDownable))
					{
						tAction.Set(TargetOptions.KnockDown);
						attacker.Shove(target, KnockbackDistance);
					}
				}
			}

			// Update current weapon
			SkillHelper.UpdateWeapon(attacker, targets.FirstOrDefault(), ProficiencyGainType.Melee, attacker.RightHand);

			cap.Handle();

			Send.Effect(attacker, Effect.LightningRod, (int)LightningRodEffect.Attack, poe.X, poe.Y);

			Send.SkillUse(attacker, skill.Info.Id, targetAreaId, 0, 1);
			skill.Train(1); // Use the Skill

			attacker.Region.RemoveProp(lProp);
		}
Esempio n. 13
0
File: Door.cs Progetto: xKamuna/aura
		/// <summary>
		/// Door's behavior when it's not locked.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="prop"></param>
		private void WarpInside(Creature creature, Prop prop)
		{
			var creaturePos = creature.GetPosition();
			var cCoord = new Position(creaturePos.X / Dungeon.TileSize, creaturePos.Y / Dungeon.TileSize);

			if (cCoord == _closedFrom)
			{
				Send.Notice(creature, NoticeType.MiddleSystem, Localization.Get("There is a monster still standing.\nYou must defeat all the monsters for the door to open."));
				return;
			}

			var x = _closedFrom.X * Dungeon.TileSize + Dungeon.TileSize / 2;
			var y = _closedFrom.Y * Dungeon.TileSize + Dungeon.TileSize / 2;

			if (cCoord.X < _closedFrom.X)
				x -= 1000;
			else if (cCoord.X > _closedFrom.X)
				x += 1000;
			else if (cCoord.Y < _closedFrom.Y)
				y -= 1000;
			else if (cCoord.Y > _closedFrom.Y)
				y += 1000;

			creature.SetPosition(x, y);
			Send.SetLocation(creature, x, y);
		}
Esempio n. 14
0
		public virtual void OnPropEvent(Puzzle puzzle, Prop prop)
		{
		}
Esempio n. 15
0
        /// <summary>
        /// Adds all props found in the client for this region.
        /// </summary>
        private void LoadClientProps()
        {
            if (_regionData == null || _regionData.Areas == null)
                return;

            foreach (var area in _regionData.Areas.Values)
            {
                foreach (var prop in area.Props.Values)
                {
                    var add = new Prop(prop.EntityId, "", "", "", prop.Id, this.Id, (int)prop.X, (int)prop.Y, prop.Direction, prop.Scale, 0);

                    // Add drop behaviour if drop type exists
                    var dropType = prop.GetDropType();
                    if (dropType != -1) add.Behavior = Prop.GetDropBehavior(dropType);

                    this.AddProp(add);
                }
            }
        }
Esempio n. 16
0
        /// <summary>
        /// Despawns prop, sends EntityDisappears.
        /// </summary>
        public void RemoveProp(Prop prop)
        {
            if (!prop.ServerSide)
            {
                Log.Error("RemoveProp: Client side props can't be removed.");
                prop.DisappearTime = DateTime.MinValue;
                return;
            }

            _propsRWLS.EnterWriteLock();
            try
            {
                _props.Remove(prop.EntityId);
            }
            finally
            {
                _propsRWLS.ExitWriteLock();
            }

            Send.PropDisappears(prop);

            prop.Region = null;
        }
Esempio n. 17
0
        /// <summary>
        ///  Spawns prop, sends EntityAppears.
        /// </summary>
        public void AddProp(Prop prop)
        {
            _propsRWLS.EnterWriteLock();
            try
            {
                _props.Add(prop.EntityId, prop);
            }
            finally
            {
                _propsRWLS.ExitWriteLock();
            }

            prop.Region = this;

            Send.EntityAppears(prop);
        }
Esempio n. 18
0
		/// <summary>
		/// Adds all props found in the client for this region.
		/// </summary>
		protected void LoadProps()
		{
			foreach (var area in this.RegionInfoData.Areas)
			{
				foreach (var prop in area.Props.Values)
				{
					var add = new Prop(prop.EntityId, prop.Id, this.Id, (int)prop.X, (int)prop.Y, prop.Direction, prop.Scale, 0, "", "", "");

					// Add copy of extensions
					foreach (var para in prop.Parameters)
						add.Extensions.AddSilent(new PropExtension(para.SignalType, para.EventType, para.Name, 0));

					// Add drop behaviour if drop type exists
					var dropType = prop.GetDropType();
					if (dropType != -1) add.Behavior = Prop.GetDropBehavior(dropType);

					// Replace default shapes with the ones loaded from region.
					add.Shapes.Clear();
					add.Shapes.AddRange(prop.Shapes.Select(a => a.GetPoints(0, 0, 0)));

					this.AddProp(add);
				}
			}
		}
Esempio n. 19
0
		/// <summary>
		/// Initiates floor, creating puzzles and props.
		/// </summary>
		/// <param name="iRegion"></param>
		public void InitFloorRegion(int iRegion)
		{
			this.CreatePuzzles(iRegion);

			var region = this.Regions[iRegion];
			var floor = this.Generator.Floors[iRegion - 1];
			var gen = floor.MazeGenerator;
			var floorData = this.Data.Floors[iRegion - 1];

			var iPrevRegion = iRegion - 1;
			var iNextRegion = iRegion + 1;

			var startTile = gen.StartPos;
			var startPos = new Generation.Position(startTile.X * Dungeon.TileSize + Dungeon.TileSize / 2, startTile.Y * Dungeon.TileSize + Dungeon.TileSize / 2);
			var startRoomTrait = floor.GetRoom(startTile);
			var startRoomIncomingDirection = startRoomTrait.GetIncomingDirection();

			var endTile = gen.EndPos;
			var endPos = new Generation.Position(endTile.X * Dungeon.TileSize + Dungeon.TileSize / 2, endTile.Y * Dungeon.TileSize + Dungeon.TileSize / 2);
			var endRoomTrait = floor.GetRoom(endTile);
			var endRoomDirection = 0;
			for (int dir = 0; dir < 4; ++dir)
			{
				if (endRoomTrait.Links[dir] == LinkType.To)
				{
					endRoomDirection = dir;
					break;
				}
			}

			// Create upstairs prop
			var stairsBlock = this.Data.Style.Get(DungeonBlockType.StairsUp, startRoomIncomingDirection);
			var stairs = new Prop(stairsBlock.PropId, region.Id, startPos.X, startPos.Y, MabiMath.DegreeToRadian(stairsBlock.Rotation), 1, 0, "single");
			stairs.Info.Color1 = floorData.Color1;
			stairs.Info.Color2 = floorData.Color1;
			stairs.Info.Color3 = floorData.Color3;
			region.AddProp(stairs);

			// Create portal prop leading to prev floor
			var portalBlock = this.Data.Style.Get(DungeonBlockType.PortalUp, startRoomIncomingDirection);
			var portal = new Prop(portalBlock.PropId, region.Id, startPos.X, startPos.Y, MabiMath.DegreeToRadian(portalBlock.Rotation), 1, 0, "single", "_upstairs", Localization.Get("<mini>TO</mini> Upstairs"));
			portal.Info.Color1 = floorData.Color1;
			portal.Info.Color2 = floorData.Color1;
			portal.Info.Color3 = floorData.Color3;
			portal.Behavior = (cr, pr) =>
			{
				// Indoor_RDungeon_EB marks the end position on the prev floor.
				var clientEvent = this.Regions[iPrevRegion].GetClientEvent("Indoor_RDungeon_EB");
				if (clientEvent == null)
				{
					Log.Error("Event 'Indoor_RDungeon_EB' not found while trying to warp to '{0}'.", this.Regions[iPrevRegion].Name);
					return;
				}

				// Warp to prev region
				var regionId = this.Regions[iPrevRegion].Id;
				var x = (int)clientEvent.Data.X;
				var y = (int)clientEvent.Data.Y;

				cr.Warp(regionId, x, y);
			};
			region.AddProp(portal);

			// Create save statue
			var saveStatue = new Prop(this.Data.SaveStatuePropId, region.Id, startPos.X, startPos.Y, MabiMath.DegreeToRadian(stairsBlock.Rotation + 180), 1, 0, "single");
			saveStatue.Info.Color1 = floorData.Color1;
			saveStatue.Info.Color2 = floorData.Color1;
			saveStatue.Info.Color3 = floorData.Color3;
			saveStatue.Behavior = (cr, pr) =>
			{
				cr.DungeonSaveLocation = cr.GetLocation();
				Send.Notice(cr, Localization.Get("You have memorized this location."));

				// Scroll message
				var msg = string.Format("You're currently on Floor {0} of {1}. ", iRegion, this.Data.EngName);
				Send.Notice(cr, NoticeType.Top, ScrollMessageDuration, msg + this.GetPlayerListScrollMessage());
			};
			region.AddProp(saveStatue);

			// Spawn boss or downstair props
			// TODO: There is one dungeon that has two boss rooms.
			if (floor.IsLastFloor)
			{
				// Create door to treasure room
				_bossExitDoor = new Prop(this.Data.BossExitDoorId, region.Id, endPos.X, endPos.Y + Dungeon.TileSize / 2, Rotation(Direction.Up), 1, 0, "closed");
				_bossExitDoor.Info.Color1 = floorData.Color1;
				_bossExitDoor.Info.Color2 = floorData.Color1;
				_bossExitDoor.Info.Color3 = floorData.Color3;
				region.AddProp(_bossExitDoor);

				// Get or create boss door
				if (endRoomTrait.PuzzleDoors[Direction.Down] == null)
				{
					Log.Warning("Dungeon.InitFloorRegion: No locked place in last section of '{0}'.", this.Name);

					_bossDoor = new Door(this.Data.BossDoorId, region.Id, endPos.X, endPos.Y - Dungeon.TileSize, Direction.Up, DungeonBlockType.BossDoor, "", "closed");
					_bossDoor.Info.Color1 = floorData.Color1;
					_bossDoor.Info.Color2 = floorData.Color1;
					_bossDoor.Info.Color3 = floorData.Color3;
					_bossDoor.Behavior = (cr, pr) => { _bossDoor.Open(); };
					_bossDoor.Behavior += this.BossDoorBehavior;
					_bossDoor.UpdateShapes();
					endRoomTrait.PuzzleDoors[Direction.Down] = _bossDoor; // making sure another open dummy door won't be added here
					region.AddProp(_bossDoor);
				}
				else
				{
					_bossDoor = endRoomTrait.PuzzleDoors[Direction.Down];
				}

				// Create exit statue
				var exitStatue = new Prop(this.Data.LastStatuePropId, region.Id, endPos.X, endPos.Y + Dungeon.TileSize * 2, Rotation(Direction.Up), 1, 0, "single");
				exitStatue.Info.Color1 = floorData.Color1;
				exitStatue.Info.Color2 = floorData.Color1;
				exitStatue.Info.Color3 = floorData.Color3;
				exitStatue.Extensions.AddSilent(new ConfirmationPropExtension("GotoLobby", "_LT[code.standard.msg.dungeon_exit_notice_msg]", "_LT[code.standard.msg.dungeon_exit_notice_title]", "haskey(chest)"));
				exitStatue.Behavior = (cr, pr) => { cr.Warp(this.Data.Exit); };
				region.AddProp(exitStatue);
			}
			else
			{
				// Create downstairs prop
				var stairsDownBlock = this.Data.Style.Get(DungeonBlockType.StairsDown, endRoomDirection);
				var stairsDown = new Prop(stairsDownBlock.PropId, region.Id, endPos.X, endPos.Y, MabiMath.DegreeToRadian(stairsDownBlock.Rotation), 1, 0, "single");
				stairsDown.Info.Color1 = floorData.Color1;
				stairsDown.Info.Color2 = floorData.Color1;
				stairsDown.Info.Color3 = floorData.Color3;
				region.AddProp(stairsDown);

				// Create portal leading to the next floor
				var portalDownBlock = this.Data.Style.Get(DungeonBlockType.PortalDown, endRoomDirection);
				var portalDown = new Prop(portalDownBlock.PropId, region.Id, endPos.X, endPos.Y, MabiMath.DegreeToRadian(portalDownBlock.Rotation), 1, 0, "single", "_downstairs", Localization.Get("<mini>TO</mini> Downstairs"));
				portalDown.Info.Color1 = floorData.Color1;
				portalDown.Info.Color2 = floorData.Color1;
				portalDown.Info.Color3 = floorData.Color3;
				portalDown.Behavior = (cr, pr) =>
				{
					// Indoor_RDungeon_SB marks the start position on the next floor.
					var clientEvent = this.Regions[iNextRegion].GetClientEvent("Indoor_RDungeon_SB");
					if (clientEvent == null)
					{
						Log.Error("Event 'Indoor_RDungeon_SB' not found while trying to warp to '{0}'.", this.Regions[iNextRegion].Name);
						return;
					}

					// Warp to next floor
					var regionId = this.Regions[iNextRegion].Id;
					var x = (int)clientEvent.Data.X;
					var y = (int)clientEvent.Data.Y;

					cr.Warp(regionId, x, y);
				};
				region.AddProp(portalDown);
			}

			// Place dummy doors
			for (int x = 0; x < floor.MazeGenerator.Width; ++x)
			{
				for (int y = 0; y < floor.MazeGenerator.Height; ++y)
				{
					var room = floor.MazeGenerator.GetRoom(x, y);
					var roomTrait = floor.GetRoom(x, y);
					var isRoom = (roomTrait.RoomType >= RoomType.Start);

					if (!room.Visited || !isRoom)
						continue;

					for (var dir = 0; dir < 4; ++dir)
					{
						// Skip stairs
						if (roomTrait.RoomType == RoomType.Start && dir == startRoomIncomingDirection)
							continue;
						if (roomTrait.RoomType == RoomType.End && dir == endRoomDirection)
							continue;

						if (roomTrait.Links[dir] == LinkType.None)
							continue;

						if (roomTrait.PuzzleDoors[dir] == null)
						{
							var doorX = x * Dungeon.TileSize + Dungeon.TileSize / 2;
							var doorY = y * Dungeon.TileSize + Dungeon.TileSize / 2;

							var doorBlock = this.Data.Style.Get(DungeonBlockType.Door, dir);
							var doorProp = new Prop(doorBlock.PropId, region.Id, doorX, doorY, MabiMath.DegreeToRadian(doorBlock.Rotation), state: "open");
							doorProp.Info.Color1 = floorData.Color1;
							doorProp.Info.Color2 = floorData.Color2;
							doorProp.Info.Color3 = floorData.Color3;
							region.AddProp(doorProp);
						}
						else if (roomTrait.PuzzleDoors[dir].EntityId == 0)
						{
							// Add doors from failed puzzles
							roomTrait.PuzzleDoors[dir].Info.Region = region.Id;
							region.AddProp(roomTrait.PuzzleDoors[dir]);
						}
					}
				}
			}
		}
Esempio n. 20
0
		/// <summary>
		/// Broadcasts prop extension remove.
		/// </summary>
		/// <param name="prop"></param>
		/// <param name="ext"></param>
		public static void RemovePropExtension(Prop prop, PropExtension ext)
		{
			var packet = new Packet(Op.RemovePropExtension, prop.EntityId);
			packet.PutString(ext.Name);

			prop.Region.Broadcast(packet);
		}
Esempio n. 21
0
File: Chest.cs Progetto: Vinna/aura
		protected override void DefaultBehavior(Creature creature, Prop prop)
		{
			// Make sure the chest was still closed when it was clicked.
			// No security violation because it could be caused by lag.
			if (prop.State == "open")
				return;

			// Check key
			var key = creature.Inventory.GetItem(a => a.Info.Id == 70028 && a.MetaData1.GetString("prop_to_unlock") == this.LockName);
			if (key == null)
			{
				Send.Notice(creature, Localization.Get("There is no matching key."));
				return;
			}

			// Remove key
			creature.Inventory.Remove(key);

			// Open and drop
			prop.SetState("open");
			this.DropItems(creature);
		}
Esempio n. 22
0
		/// <summary>
		/// Generates areas, incl (client) props and events.
		/// </summary>
		private void GenerateAreas()
		{
			this.Data = new RegionInfoData();

			var areaId = 2;
			var floor = this.Floor;

			for (int x = 0; x < floor.MazeGenerator.Width; ++x)
			{
				for (int y = 0; y < floor.MazeGenerator.Height; ++y)
				{
					var room = floor.MazeGenerator.GetRoom(x, y);
					var roomTrait = floor.GetRoom(x, y);

					if (!room.Visited)
						continue;

					var isStart = (roomTrait.RoomType == RoomType.Start);
					var isEnd = (roomTrait.RoomType == RoomType.End);
					var isRoom = (roomTrait.RoomType >= RoomType.Start);
					var isBossRoom = (floor.HasBossRoom && isEnd);
					var eventId = 0L;

					if (!isBossRoom)
					{
						var areaData = new AreaData();
						areaData.Id = areaId++;
						areaData.Name = "Tile" + areaData.Id;

						areaData.X1 = x * Dungeon.TileSize;
						areaData.Y1 = y * Dungeon.TileSize;
						areaData.X2 = x * Dungeon.TileSize + Dungeon.TileSize;
						areaData.Y2 = y * Dungeon.TileSize + Dungeon.TileSize;

						this.Data.Areas.Add(areaData);

						var type = (isRoom ? DungeonBlockType.Room : DungeonBlockType.Alley);

						var propEntityId = MabiId.ClientProps | ((long)this.Id << 32) | ((long)areaData.Id << 16) | 1;
						var block = this.Dungeon.Data.Style.Get(type, room.Directions);
						var tileCenter = new Point(x * Dungeon.TileSize + Dungeon.TileSize / 2, y * Dungeon.TileSize + Dungeon.TileSize / 2);

						var prop = new Prop(propEntityId, block.PropId, this.Id, tileCenter.X, tileCenter.Y, MabiMath.DegreeToRadian(block.Rotation), 1, 0, "", "", "");
						this.AddProp(prop);

						// Debug
						//foreach (var points in prop.Shapes)
						//{
						//	foreach (var point in points)
						//	{
						//		var pole = new Prop(30, this.Id, point.X, point.Y, 0, 1, 0, "", "", "");
						//		pole.Shapes.Clear();
						//		this.AddProp(pole);
						//	}
						//}

						// TODO: This region/data stuff is a mess... create
						//   proper classes, put them in the regions and be
						//   done with it.

						if (isStart || isEnd)
						{
							var xp = tileCenter.X;
							var yp = tileCenter.Y;

							if (roomTrait.DoorType[Direction.Up] >= 3000)
								yp += 400;
							else if (roomTrait.DoorType[Direction.Right] >= 3000)
								xp += 400;
							else if (roomTrait.DoorType[Direction.Down] >= 3000)
								yp -= 400;
							else if (roomTrait.DoorType[Direction.Left] >= 3000)
								xp -= 400;

							var eventData = new EventData();
							eventData.Id = MabiId.AreaEvents | ((long)this.Id << 32) | ((long)areaData.Id << 16) | eventId++;
							eventData.Name = (isStart ? "Indoor_RDungeon_SB" : "Indoor_RDungeon_EB");
							eventData.X = xp;
							eventData.Y = yp;

							var shape = new ShapeData();
							shape.DirX1 = 1;
							shape.DirY2 = 1;
							shape.LenX = 100;
							shape.LenY = 100;
							shape.PosX = xp;
							shape.PosY = yp;
							eventData.Shapes.Add(shape);

							areaData.Events.Add(eventData.Id, eventData);
							_clientEvents.Add(eventData.Id, new ClientEvent(eventData, this.Data.Name, areaData.Name));
						}
					}
					else
					{
						// Big main room
						var areaData = new AreaData();
						areaData.Id = areaId++;
						areaData.Name = "Tile" + areaData.Id;

						areaData.X1 = x * Dungeon.TileSize - Dungeon.TileSize;
						areaData.Y1 = y * Dungeon.TileSize;
						areaData.X2 = x * Dungeon.TileSize + Dungeon.TileSize * 2;
						areaData.Y2 = y * Dungeon.TileSize + Dungeon.TileSize * 2;

						this.Data.Areas.Add(areaData);

						var block = this.Dungeon.Data.Style.Get(DungeonBlockType.BossRoom);
						var propEntityId = MabiId.ClientProps | ((long)this.Id << 32) | ((long)areaData.Id << 16) | 1;
						var tileCenter = new Point(x * Dungeon.TileSize + Dungeon.TileSize / 2, y * Dungeon.TileSize + Dungeon.TileSize);

						var prop = new Prop(propEntityId, block.PropId, this.Id, tileCenter.X, tileCenter.Y, MabiMath.DegreeToRadian(block.Rotation), 1, 0, "", "", "");
						this.AddProp(prop);

						// Debug
						//foreach (var points in prop.Shapes)
						//{
						//	foreach (var point in points)
						//	{
						//		var pole = new Prop(30, this.Id, point.X, point.Y, 0, 1, 0, "", "", "");
						//		pole.Shapes.Clear();
						//		this.AddProp(pole);
						//	}
						//}

						// Treasure room
						areaData = new AreaData();
						areaData.Id = areaId++;
						areaData.Name = "Tile" + areaData.Id;

						areaData.X1 = x * Dungeon.TileSize;
						areaData.Y1 = y * Dungeon.TileSize + Dungeon.TileSize * 2;
						areaData.X2 = x * Dungeon.TileSize + Dungeon.TileSize;
						areaData.Y2 = y * Dungeon.TileSize + Dungeon.TileSize * 2 + Dungeon.TileSize;

						this.Data.Areas.Add(areaData);
					}
				}
			}
		}
Esempio n. 23
0
		protected void ShootFirework(Location location, FireworkType type, string message)
		{
			var region = ChannelServer.Instance.World.GetRegion(location.RegionId);
			if (region == null)
			{
				Log.Warning(this.GetType().Name + ".ShootFirework: Unknown region.");
				return;
			}

			if (message == null)
				message = "";

			var delay = 500;
			var rnd = RandomProvider.Get();
			var height = rnd.Between(750, 2000);
			var heightf = height / 100f;

			var prop = new Prop(208, location.RegionId, location.X, location.Y, 0);
			prop.DisappearTime = DateTime.Now.AddMilliseconds(20000 + delay);
			region.AddProp(prop);

			Task.Delay(delay).ContinueWith(__ =>
			{
				prop.Xml.SetAttributeValue("height", height);
				prop.Xml.SetAttributeValue("message", message + " (" + heightf.ToString("0.##") + "m)");
				prop.Xml.SetAttributeValue("type", (int)type);
				prop.Xml.SetAttributeValue("seed", Interlocked.Increment(ref _fireworkSeed));
				Send.PropUpdate(prop);
			});
		}
Esempio n. 24
0
        /// <summary>
        /// Creates sitting prop, fails silently if item or chair
        /// data doesn't exist.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="chairItemEntityId"></param>
        private void SetUpChair(Creature creature, long chairItemEntityId)
        {
            if (chairItemEntityId == 0)
                return;

            // Check item
            var item = creature.Inventory.GetItem(chairItemEntityId);
            if (item == null || item.Data.Type != ItemType.Misc)
                return;

            // Get chair data
            var chairData = AuraData.ChairDb.Find(item.Info.Id);
            if (chairData == null)
                return;

            var pos = creature.GetPosition();

            // Effect
            if (chairData.Effect != 0)
                Send.Effect(creature, chairData.Effect, true);

            // Chair prop
            var sittingProp = new Prop((!creature.IsGiant ? chairData.PropId : chairData.GiantPropId), creature.RegionId, pos.X, pos.Y, MabiMath.ByteToRadian(creature.Direction));
            sittingProp.Info.Color1 = item.Info.Color1;
            sittingProp.Info.Color2 = item.Info.Color2;
            sittingProp.Info.Color3 = item.Info.Color3;
            sittingProp.State = "stand";
            creature.Region.AddProp(sittingProp);

            // Move char
            Send.AssignSittingProp(creature, sittingProp.EntityId, 1);

            // Update chair
            sittingProp.XML = string.Format("<xml OWNER='{0}' SITCHAR='{0}'/>", creature.EntityId);
            Send.PropUpdate(sittingProp);

            creature.Temp.CurrentChairData = chairData;
            creature.Temp.SittingProp = sittingProp;
        }
Esempio n. 25
0
		/// <summary>
		/// Generates entity id for prop.
		/// </summary>
		/// <param name="prop"></param>
		/// <returns></returns>
		private long GetNewPropEntityId(Prop prop)
		{
			var regionId = this.Id;
			var areaId = this.GetAreaId((int)prop.Info.X, (int)prop.Info.Y);
			var propId = 0;

			lock (_propIds)
			{
				if (!_propIds.ContainsKey(areaId))
					_propIds[areaId] = 1;

				propId = _propIds[areaId]++;

				if (propId >= ushort.MaxValue)
					throw new Exception("Max prop id reached in region '" + regionId + "', area '" + areaId + "'.");
			}

			var result = MabiId.ServerProps;
			result |= (long)regionId << 32;
			result |= (long)areaId << 16;
			result |= (ushort)propId;

			return result;
		}
Esempio n. 26
0
        /// <summary>
        /// Handles item burning, retruns whether it was successful.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="item"></param>
        /// <param name="campfire"></param>
        /// <param name="enchantersBurn"></param>
        public bool Burn(Creature creature, Item item, Prop campfire, bool enchantersBurn)
        {
            var skill = creature.Skills.Get(SkillId.Enchant);
            var enchantBurnSuccess = false;
            var powderBurnSuccess = false;
            var exp = 0;

            // Enchanter's Burn
            if (enchantersBurn)
            {
                var rnd = RandomProvider.Get();

                var isEquip = item.HasTag("/equip/");
                var hasEnchantBurnItems = (creature.Inventory.Has(51102) && creature.Inventory.Has(63016)); // Mana Herb + Holy Water

                // Enchant burning
                if (!isEquip || !hasEnchantBurnItems)
                {
                    // Unofficial
                    Send.SystemMessage(creature, Localization.Get("You don't the necessary items."));
                    return false;
                }

                // Get chances
                // All unofficial
                var rank = (skill == null ? 16 : (int)skill.Info.Rank);
                var enchantChance = (skill == null ? 0 : skill.RankData.Var3);

                // Campfire r8+ bonus
                if (enchantChance > 0 && campfire.Temp.CampfireSkillRank.Rank >= SkillRank.R8)
                    enchantChance += (16 - rank);

                // Powder = double enchant chance, based on the Wiki saying
                // r1 doesn't guarantee getting the enchants, but it does
                // guarantee getting powder.
                var powderChance = enchantChance * 2;

                // Debug
                if (creature.Titles.SelectedTitle == TitleId.devCAT)
                    Send.ServerMessage(creature, "Debug: Chance for enchant: {0:0}, chance for powder: {1:0}", enchantChance, powderChance);

                // Try prefix
                if (item.OptionInfo.Prefix != 0 && rnd.Next(100) < enchantChance)
                {
                    var enchant = Item.CreateEnchant(item.OptionInfo.Prefix);
                    creature.AcquireItem(enchant);
                    enchantBurnSuccess = true;
                }

                // Try suffix
                if (item.OptionInfo.Suffix != 0 && rnd.Next(100) < enchantChance)
                {
                    var enchant = Item.CreateEnchant(item.OptionInfo.Suffix);
                    creature.AcquireItem(enchant);
                    enchantBurnSuccess = true;
                }

                // Try suffix
                if (item.OptionInfo.Prefix + item.OptionInfo.Suffix != 0 && rnd.Next(100) < powderChance)
                {
                    var powder = new Item(62003); // Blessed Magic Powder
                    creature.AcquireItem(powder);
                    powderBurnSuccess = true;
                }

                // Reduce items
                creature.Inventory.Remove(51102, 1); // Mana Herb
                creature.Inventory.Remove(63016, 1); // Holy Water

                // Training
                this.BurnTraining(skill, enchantBurnSuccess, powderBurnSuccess);

                // Success/Fail motion
                Send.UseMotion(creature, 14, enchantBurnSuccess ? 0 : 3);
            }

            // Add exp based on item buying price (random+unofficial)
            if (item.OptionInfo.Price > 0)
            {
                exp = 40 + (int)(item.OptionInfo.Price / (float)item.Data.StackMax / 100f * item.Info.Amount);
                creature.GiveExp(exp);
            }

            // Remove item from cursor
            creature.Inventory.Remove(item);

            // Effect
            Send.Effect(MabiId.Broadcast, creature, Effect.BurnItem, campfire.EntityId, enchantBurnSuccess);
            Send.Notice(creature, NoticeType.MiddleSystem, Localization.Get("Burning EXP {0}"), exp);

            return true;
        }
Esempio n. 27
0
		/// <summary>
		/// Completes skill, placing the campfire.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="skill"></param>
		/// <param name="packet"></param>
		public void Complete(Creature creature, Skill skill, Packet packet)
		{
			var positionId = packet.GetLong();
			var unkInt1 = packet.GetInt();
			var unkInt2 = packet.GetInt();
			var propId = PropId;

			// Handle items
			if (skill.Info.Id == SkillId.Campfire)
			{
				// Check Firewood, the client should stop the player long before Complete.
				if (creature.Inventory.Count(creature.Temp.FirewoodItemId) < FirewoodCost)
					throw new ModerateViolation("Used Campfire without Firewood.");

				// Remove Firewood
				creature.Inventory.Remove(creature.Temp.FirewoodItemId, FirewoodCost);
			}
			else
			{
				// Check kit
				var item = creature.Inventory.GetItem(creature.Temp.CampfireKitItemEntityId);
				if (item == null)
					throw new ModerateViolation("Used CampfireKit with invalid kit.");

				propId = this.GetPropId(item); // Change the prop ID based on what campfire kit was used

				// Reduce kit
				creature.Inventory.Decrement(item);
			}

			// Set up Campfire
			var pos = new Position(positionId);
			var effect = (skill.Info.Rank < SkillRank.RB ? "campfire_01" : "campfire_02");
			var prop = new Prop(propId, creature.RegionId, pos.X, pos.Y, MabiMath.ByteToRadian(creature.Direction), 1); // Logs
			prop.State = "single";
			if (prop.Data.Id != HalloweenPropId)
				prop.Xml.SetAttributeValue("EFFECT", effect); // Fire effect
			prop.DisappearTime = DateTime.Now.AddMinutes(this.GetDuration(skill.Info.Rank, creature.RegionId)); // Disappear after x minutes

			// Temp data for Rest
			prop.Temp.CampfireSkillRank = skill.RankData;
			if (skill.Info.Id == SkillId.Campfire)
				prop.Temp.CampfireFirewood = AuraData.ItemDb.Find(creature.Temp.FirewoodItemId);

			creature.Region.AddProp(prop);

			// Training
			if (skill.Info.Rank == SkillRank.Novice)
				skill.Train(1); // Use Campfire.

			// Complete
			Send.SkillComplete(creature, skill.Info.Id, positionId, unkInt1, unkInt2);
		}
Esempio n. 28
0
		/// <summary>
		/// Adds all props found in the client for this region.
		/// </summary>
		protected void LoadProps()
		{
			foreach (var areaData in this.Data.Areas)
			{
				foreach (var propData in areaData.Props.Values)
				{
					var prop = new Prop(propData, this.Id, this.Data.Name, areaData.Name);

					this.AddProp(prop);
				}
			}
		}
Esempio n. 29
0
		/// <summary>
		/// Behavior for this dungeon's boss door.
		/// </summary>
		/// <param name="_"></param>
		/// <param name="prop"></param>
		public void BossDoorBehavior(Creature _, Prop prop)
		{
			// Get door
			var door = prop as Door;
			if (door == null)
			{
				Log.Error("Dungeon.BossDoorBehavior: Boss door... is not a door!?");
				return;
			}

			// Make sure it got unlocked
			if (door.IsLocked)
				return;

			// Check if bosses were already spawned
			if (_bossSpawned)
				return;
			_bossSpawned = true;

			// Remove all monsters
			this.Regions.ForEach(a => a.RemoveAllMonsters());

			// Call OnBoss
			if (this.Script != null)
				this.Script.OnBoss(this);

			// Open boss and exit door if no bosses were spawned
			if (_bossesRemaining == 0)
			{
				_bossDoor.SetState("open");
				_bossExitDoor.SetState("open");
			}
		}
Esempio n. 30
0
		/// <summary>
		///  Spawns prop, sends EntityAppears.
		/// </summary>
		public void AddProp(Prop prop)
		{
			// Generate prop id if it doesn't have one yet.
			if (prop.EntityId == 0)
				prop.EntityId = this.GetNewPropEntityId(prop);

			_propsRWLS.EnterWriteLock();
			try
			{
				if (_props.ContainsKey(prop.EntityId))
					throw new ArgumentException("A prop with id '" + prop.EntityId.ToString("X16") + "' already exists.");

				_props.Add(prop.EntityId, prop);
			}
			finally
			{
				_propsRWLS.ExitWriteLock();
			}

			prop.Region = this;

			// Add collisions
			this.Collisions.Add(prop);

			//Send.EntityAppears(prop);
		}