private void PrepareTrainers(Creature challenger, Creature player) { var pos = challenger.GetPosition(); var playerNewPos = pos.GetRelative(MabiMath.ByteToRadian(challenger.Direction), BattleDistance); _challengerMonsterPos = playerNewPos.GetRelative(pos, -MonsterDistance); _playerMonsterPos = pos.GetRelative(playerNewPos, -MonsterDistance); //challenger.Region.AddProp(new Prop(10, challenger.RegionId, _challengerMonsterPos.X, _challengerMonsterPos.Y, 0)); //challenger.Region.AddProp(new Prop(10, challenger.RegionId, _playerMonsterPos.X, _playerMonsterPos.Y, 0)); // Camera var packet = new Packet(Op.SetCamera, player.EntityId); packet.PutFloat(1000); // distance packet.PutFloat(0); packet.PutFloat(5); // pitch packet.PutFloat(MabiMath.DirectionToRadian(pos.X - playerNewPos.X, pos.Y - playerNewPos.Y) * (180 / Math.PI) + 25); // yaw packet.PutFloat(0); player.Client.Send(packet); // Move and turn player.Jump(playerNewPos); player.TurnTo(pos); challenger.TurnTo(playerNewPos); }
public void GetRelative() { var pos1 = new Position(100, 100); var pos2 = new Position(100, 200); Assert.Equal(new Position(100, 250), pos1.GetRelative(pos2, 50)); Assert.Equal(new Position(100, 150), pos1.GetRelative(pos2, -50)); Assert.Equal(new Position(100, -50), pos1.GetRelative(pos2, -250)); var pos3 = new Position(50, 100); Assert.Equal(new Position(0, 100), pos1.GetRelative(pos3, 50)); Assert.Equal(new Position(100, 100), pos1.GetRelative(pos3, -50)); Assert.Equal(new Position(300, 100), pos1.GetRelative(pos3, -250)); var up = MabiMath.DegreeToRadian(90); var down = MabiMath.DegreeToRadian(270); var left = MabiMath.DegreeToRadian(180); var right = MabiMath.DegreeToRadian(0); Assert.Equal(new Position(100, 200), pos1.GetRelative(up, 100)); Assert.Equal(new Position(100, 0), pos1.GetRelative(down, 100)); Assert.Equal(new Position(0, 100), pos1.GetRelative(left, 100)); Assert.Equal(new Position(200, 100), pos1.GetRelative(right, 100)); }
/// <summary> /// Sets up shop, spawning the prop. /// </summary> /// <param name="title"></param> /// <param name="description"></param> public bool SetUp(string title, string description) { if (!this.IsReadyForBusiness) { return(false); } this.Title = title; this.Description = description; var rnd = RandomProvider.Get(); var pos = this.Owner.GetPosition(); var location = new Location(this.Owner.RegionId, GetPlacementPosition(pos, this.Owner.Direction)); var direction = MabiMath.ByteToRadian(this.Owner.Direction); // Spawn prop var propId = GetShopPropId(this.Bag); this.Prop = new Prop(propId, location.RegionId, location.X, location.Y, (float)direction); this.Prop.Info.Color1 = this.Bag.Info.Color1; this.Prop.Info.Color2 = this.Bag.Info.Color2; this.Prop.Info.Color3 = this.Bag.Info.Color3; this.Prop.Extensions.AddSilent(new ConfirmationPropExtension("default", "이 개인상점을 여시겠습니까?", "개인상점 열기")); this.Region.AddProp(this.Prop); // Move that body Send.UseMotion(this.Owner, 11, 4); // Update prop with owner and title this.Prop.Xml.SetAttributeValue("PSPID", this.Owner.EntityId); this.Prop.Xml.SetAttributeValue("PSTTL", title); Send.PropUpdate(this.Prop); return(true); }
protected override IEnumerable Idle() { var challenger = Creature; if (challenger.Vars.Temp["inTrainerBattleWith"] != null) { Return(); } var dir = MabiMath.ByteToRadian(challenger.Direction) - Math.PI; // opposite direction...? var pos = challenger.GetPosition(); var players = challenger.Region.GetCreatures(a => a.IsPlayer && a.GetPosition().InCone(pos, dir, 1000, 45)); if (players.Count != 1) { Return(); } var opponent = players.First(); if (_fought.Contains(opponent.EntityId)) { Return(); } _fought.Add(opponent.EntityId); TrainerBaseScript.StartBattle(challenger, opponent); }
/// <summary> /// Spawns treasure chests in treasure room. /// </summary> private void SpawnTreasureChests() { var region = this.Regions.Last(); var rnd = RandomProvider.Get(); for (int i = 0; i < _treasureChests.Count; ++i) { var pos = new Generation.Position(this.Generator.Floors.Last().MazeGenerator.EndPos); pos.X *= Dungeon.TileSize; pos.Y *= Dungeon.TileSize; pos.X += Dungeon.TileSize / 2; pos.Y += (int)(Dungeon.TileSize * 2.5f); var placement = _treasurePlacementProvider.GetPosition(); pos.X += placement[0]; pos.Y += placement[1]; var rotation = MabiMath.DegreeToRadian(placement[2]); var prop = _treasureChests[i]; prop.RegionId = region.Id; prop.Info.X = pos.X; prop.Info.Y = pos.Y; prop.Info.Direction = rotation; region.AddProp(prop); } }
/// <summary> /// Reduces hunger by amount and handles weight gain/loss /// and stat bonuses. /// </summary> /// <remarks> /// Body and stat changes are applied inside Creature, /// on MabiTick (every 5 minutes). /// </remarks> protected void Feed(Creature creature, double hunger, double weight = 0, double upper = 0, double lower = 0, double str = 0, double int_ = 0, double dex = 0, double will = 0, double luck = 0, double life = 0, double mana = 0, double stm = 0) { // Saturday: Food effects are increased. (2x weight, hunger; effects are long term) // +100%? Seems a lot, but that's what the Wiki says. if (ErinnTime.Now.Month == ErinnMonth.Samhain) { hunger *= 2; weight *= 2; upper *= 2; lower *= 2; } // Hunger var diff = creature.Hunger; creature.Hunger -= (float)hunger; diff -= creature.Hunger; // Weight (multiplicators guessed, based on packets) // Only increase weight if you eat above 0% Hunger? if (diff < hunger) { creature.Temp.WeightFoodChange += (float)weight * (weight >= 0 ? WeightChangePlus : WeightChangeMinus); creature.Temp.UpperFoodChange += (float)upper * (upper >= 0 ? WeightChangePlus : WeightChangeMinus); creature.Temp.LowerFoodChange += (float)lower * (lower >= 0 ? WeightChangePlus : WeightChangeMinus); } // Stats creature.Temp.StrFoodChange += MabiMath.FoodStatBonus(str, hunger, diff, creature.Age); creature.Temp.IntFoodChange += MabiMath.FoodStatBonus(int_, hunger, diff, creature.Age); creature.Temp.DexFoodChange += MabiMath.FoodStatBonus(dex, hunger, diff, creature.Age); creature.Temp.WillFoodChange += MabiMath.FoodStatBonus(will, hunger, diff, creature.Age); creature.Temp.LuckFoodChange += MabiMath.FoodStatBonus(luck, hunger, diff, creature.Age); }
public void InCone() { var centerPos = new Position(0, 0); var topPos = new Position(0, 500); var bottomPos = new Position(0, -500); var leftPos = new Position(-500, 0); var rightPos = new Position(500, 0); var up = MabiMath.DegreeToRadian(90); var down = MabiMath.DegreeToRadian(270); var left = MabiMath.DegreeToRadian(180); var right = MabiMath.DegreeToRadian(0); Assert.Equal(true, topPos.InCone(centerPos, up, 600, MabiMath.DegreeToRadian(10))); Assert.Equal(true, bottomPos.InCone(centerPos, down, 600, MabiMath.DegreeToRadian(10))); Assert.Equal(true, leftPos.InCone(centerPos, left, 600, MabiMath.DegreeToRadian(10))); Assert.Equal(true, rightPos.InCone(centerPos, right, 600, MabiMath.DegreeToRadian(10))); Assert.Equal(true, topPos.InCone(centerPos, up, 500, MabiMath.DegreeToRadian(10))); Assert.Equal(false, topPos.InCone(centerPos, up, 500, MabiMath.DegreeToRadian(180))); Assert.Equal(true, topPos.InCone(centerPos, up, 600, MabiMath.DegreeToRadian(180))); Assert.Equal(true, topPos.InCone(centerPos, up, 1000, MabiMath.DegreeToRadian(180))); Assert.Equal(true, topPos.InCone(centerPos, up, 1000, MabiMath.DegreeToRadian(190))); Assert.Equal(true, topPos.InCone(centerPos, up, 1000, MabiMath.DegreeToRadian(-190))); Assert.Equal(true, topPos.InCone(centerPos, up, 1000, MabiMath.DegreeToRadian(9999))); Assert.Equal(true, topPos.InCone(centerPos, up, 1000, MabiMath.DegreeToRadian(-9999))); Assert.Equal(false, topPos.InCone(centerPos, MabiMath.DegreeToRadian(45), 2000, MabiMath.DegreeToRadian(45))); Assert.Equal(true, topPos.InCone(centerPos, MabiMath.DegreeToRadian(68), 2000, MabiMath.DegreeToRadian(45))); }
/// <summary> /// Returns position for the shop, based on given position and direction. /// </summary> /// <param name="pos"></param> /// <param name="direction"></param> /// <returns></returns> private static Position GetPlacementPosition(Position pos, byte direction) { var radians = MabiMath.ByteToRadian(direction); var x = pos.X + 50 * Math.Cos(radians); var y = pos.Y + 50 * Math.Sin(radians); return(new Position((int)x, (int)y)); }
/// <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(); // 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."); } // 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"; 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); // Complete Send.SkillComplete(creature, skill.Info.Id, positionId, unkInt1, unkInt2); }
public override void OnPuzzleCreate(Puzzle puzzle) { var lockedPlace = puzzle.GetPlace("LockedPlace"); var key = puzzle.LockPlace(lockedPlace, "Boss"); var chest = new Chest(puzzle, "KeyChest"); lockedPlace.AddProp(chest, Placement.Center); chest.Info.Direction = MabiMath.DegreeToRadian(90); chest.Add(Item.Create(GoddessPass)); chest.Add(key); }
public void GetDirection() { var up = MabiMath.DegreeToRadian(90); var down = MabiMath.DegreeToRadian(270); var left = MabiMath.DegreeToRadian(180); var right = MabiMath.DegreeToRadian(0); var pos = new Position(100, 100); Assert.Equal(up, pos.GetDirection(new Position(100, 200))); Assert.Equal(down, pos.GetDirection(new Position(100, 0))); Assert.Equal(left, pos.GetDirection(new Position(0, 100))); Assert.Equal(right, pos.GetDirection(new Position(200, 100))); }
/// <summary> /// Returns the radian rotation for the given dungeon direction. /// </summary> /// <remarks> /// TODO: Move somewhere? Direction maybe? Or an extension? /// </remarks> /// <param name="direction"></param> /// <returns></returns> private static float Rotation(int direction) { switch (direction) { case Direction.Up: return(MabiMath.DirectionToRadian(0, -1)); case Direction.Down: return(MabiMath.DirectionToRadian(0, 1)); case Direction.Left: return(MabiMath.DirectionToRadian(1, 0)); case Direction.Right: return(MabiMath.DirectionToRadian(-1, 0)); } throw new ArgumentException("Invalid direction '" + direction + "'."); }
private void SpawnGate(Dungeon dungeon) { var region = dungeon.Regions.Last(); var endLocation = dungeon.GetEndRoomCenter(); var direction = MabiMath.DirectionToRadian(0, -1); var gate = new Prop(GatePropId, endLocation.RegionId, endLocation.X, endLocation.Y, direction); gate.Info.Color2 = 0xffffffff; gate.Behavior = OnTouchGate; region.AddProp(gate); var portal = new Prop(GatePortalPropId, endLocation.RegionId, endLocation.X, endLocation.Y, direction); portal.Behavior = OnTouchPortal; region.AddProp(portal); }
private void OnCharacterSelected(long entityId) { selectedCharacter = characters.FirstOrDefault(a => a.EntityId == entityId); if (selectedCharacter == null) { Debug.LogErrorFormat("Missing character '{0}'.", entityId); return; } UpdateChannels(selectedCharacter.Server); SelChannel.interactable = true; var server = selectedCharacter.Server; var name = selectedCharacter.Name; var color = MabiMath.GetNameColor(name).ToString("X6"); TxtSelectedChar.text = string.Format("<size=20>{0}</size>\n<color=#{2}>{1}</color>", server, name, color); Connection.SelectedCharacter = selectedCharacter; }
/// <summary> /// Adds prop to puzzle in place. /// </summary> /// <param name="place"></param> /// <param name="prop"></param> /// <param name="positionType"></param> public void AddProp(PuzzlePlace place, DungeonProp prop, Placement positionType) { if (this.Region == null) { throw new PuzzleException("AddProp outside of OnPuzzleCreate."); } var pos = place.GetPosition(positionType); prop.RegionId = this.Region.Id; prop.Info.X = pos[0]; prop.Info.Y = pos[1]; prop.UpdateShapes(); prop.Info.Direction = MabiMath.DegreeToRadian(pos[2]); prop.Behavior += PuzzleEvent; this.Region.AddProp(prop); this.Props[prop.Name] = prop; }
/// <summary> /// Spawns monsters from internal list. /// </summary> public void Spawn() { var rnd = RandomProvider.Get(); var region = this.Puzzle.Region; var worldPos = this.Place.GetWorldPosition(); foreach (var monster in _monsters) { var pos = this.Place.GetPosition(_spawnPosition); monster.Direction = MabiMath.DegreeToByte(pos[2]); monster.Spawn(region.Id, pos[0], pos[1]); if (monster.AI != null) { monster.AI.Activate(1000); } } }
/// <summary> /// Creates new door prop. /// </summary> /// <param name="propId"></param> /// <param name="regionId"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="direction">Direction the door faces in, in degree.</param> /// <param name="doorType"></param> /// <param name="name"></param> /// <param name="state"></param> public Door(int propId, int regionId, int x, int y, int direction, DungeonBlockType doorType, string name, string state = "open") : base(propId, regionId, x, y, direction, 1, 0, state, "", "") { this.Name = name; this.DoorType = doorType; this.BlockBoss = false; this.Behavior = this.DefaultBehavior; _isSwitchDoor = false; _closedFrom = new Position(x / Dungeon.TileSize, y / Dungeon.TileSize); // Set direction and adjust Y for boss doors if (doorType == DungeonBlockType.BossDoor) { this.Info.Direction = MabiMath.DirectionToRadian(0, 1); this.Info.Y += Dungeon.TileSize + Dungeon.TileSize / 2; } else { this.Info.Direction = MabiMath.DegreeToRadian(direction); } }
private void SpawnMonster(Creature challenger, int regionId, Position pos, Position turnPos) { var npc = (NPC)challenger; if (npc.AI != null) { npc.AI.Detach(); } npc.Direction = MabiMath.DirectionToByte(turnPos.X - pos.X, turnPos.Y - pos.Y); npc.LifeMaxBase /= LifeRatio; npc.Life = npc.LifeMax; npc.State |= CreatureStates.Spawned; npc.State |= CreatureStates.GoodNpc; if (!npc.Skills.Has(SkillId.CombatMastery)) { npc.Skills.Give(SkillId.CombatMastery, SkillRank.RF); } if (!npc.Skills.Has(SkillId.Smash)) { npc.Skills.Give(SkillId.Smash, SkillRank.RF); } if (!npc.Skills.Has(SkillId.Defense)) { npc.Skills.Give(SkillId.Defense, SkillRank.RF); } if (!npc.Skills.Has(SkillId.Counterattack)) { npc.Skills.Give(SkillId.Counterattack, SkillRank.RF); } if (!npc.Skills.Has(SkillId.Icebolt)) { npc.Skills.Give(SkillId.Icebolt, SkillRank.RF); } challenger.Warp(regionId, pos); challenger.TurnTo(turnPos); Send.SpawnEffect(SpawnEffect.Monster, regionId, pos.X, pos.Y, challenger, challenger); }
public override void OnLoad() { SetName("_<mini>NPC</mini> Piano Player"); SetRace(10001); SetFace(skin: 18, eye: 0, eyeColor: 49, lip: 48); SetLocation(52, 46224, 43756, 206); EquipItem(Pocket.Hair, 9200, 0x000000, 0, 0); EquipItem(Pocket.Face, 3900, 0, 0, 0); EquipItem(Pocket.Armor, 15001, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF); EquipItem(Pocket.Shoe, 220056, 0xFFFFFF, 0xFFFFFF, 0x000000); // Spawn piano var pos = NPC.GetPosition(); var prop = new MabiProp(44311, NPC.Region, pos.X, pos.Y, MabiMath.DirToRad(NPC.Direction)); prop.State = "stand"; prop.ExtraData = string.Format("<xml OWNER='{0}' SITCHAR='{0}'/>", NPC.Id); SpawnProp(prop); // Sit NPC.Temp.SittingProp = prop; NPC.State |= CreatureStates.SitDown; }
/// <summary> /// Reduces hunger by amount and handles weight gain/loss /// and stat bonuses. /// </summary> /// <remarks> /// Body and stat changes are applied inside Creature, /// on MabiTick (every 5 minutes). /// </remarks> protected void Feed(Creature creature, double hunger, double weight = 0, double upper = 0, double lower = 0, double str = 0, double int_ = 0, double dex = 0, double will = 0, double luck = 0, double life = 0, double mana = 0, double stm = 0) { // Hunger var diff = creature.Hunger; creature.Hunger -= (float)hunger; diff -= creature.Hunger; // Weight (multiplicators guessed, based on packets) // Only increase weight if you eat above 0% Hunger? if (diff < hunger) { creature.Temp.WeightFoodChange += (float)weight * (weight >= 0 ? WeightChangePlus : WeightChangeMinus); creature.Temp.UpperFoodChange += (float)upper * (upper >= 0 ? WeightChangePlus : WeightChangeMinus); creature.Temp.LowerFoodChange += (float)lower * (lower >= 0 ? WeightChangePlus : WeightChangeMinus); } // Stats creature.Temp.StrFoodChange += MabiMath.FoodStatBonus(str, hunger, diff, creature.Age); creature.Temp.IntFoodChange += MabiMath.FoodStatBonus(int_, hunger, diff, creature.Age); creature.Temp.DexFoodChange += MabiMath.FoodStatBonus(dex, hunger, diff, creature.Age); creature.Temp.WillFoodChange += MabiMath.FoodStatBonus(will, hunger, diff, creature.Age); creature.Temp.LuckFoodChange += MabiMath.FoodStatBonus(luck, hunger, diff, creature.Age); }
/// <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 if (floorData.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.SetPuzzleDoor(_bossDoor, Direction.Down); // making sure another open dummy door won't be added here region.AddProp(_bossDoor); } else { _bossDoor = endRoomTrait.PuzzleDoors[Direction.Down]; if (_bossDoor.State == "open") { Log.Warning("Dungeon.InitFloorRegion: Boss door was left open, closing. Dungeon: '{0}'.", this.Name); _bossDoor.Close(endRoomTrait.X, endRoomTrait.Y); } } // 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) => { ChannelServer.Instance.Events.OnPlayerClearedDungeon(cr, this); 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]); } } } } }
/// <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.SetAttributeValue("OWNER", creature.EntityId); sittingProp.Xml.SetAttributeValue("SITCHAR", creature.EntityId); Send.PropUpdate(sittingProp); creature.Temp.CurrentChairData = chairData; creature.Temp.SittingProp = sittingProp; }
/// <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); } } } }
/// <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 = chairData.State; if (chairData.Stand != -1) { sittingProp.Xml.SetAttributeValue("PMPG", chairData.Stand); sittingProp.Xml.SetAttributeValue("PMPS", true); } sittingProp.Xml.SetAttributeValue("OWNER", creature.EntityId); sittingProp.Xml.SetAttributeValue("PMUIID", chairData.ItemId); creature.Region.AddProp(sittingProp); // State transition if (chairData.NextState != null) { Task.Delay(chairData.StateChangeDelay).ContinueWith(_ => { sittingProp.State = chairData.NextState; Send.PropUpdate(sittingProp); }); } this.SitOnProp(creature, sittingProp, chairData); }
void Update() { // Go through all entities foreach (Transform entityTransform in EntityList) { // Get entity info component, ignore empty names var entityInfo = entityTransform.GetComponent <EntityInfo>(); if (string.IsNullOrEmpty(entityInfo.Name)) { continue; } // Get information for placement var nameTarget = entityTransform.FindChild("NameTarget"); var pos = mainCamera.WorldToScreenPoint(nameTarget.transform.position); // Create new name object if new entity Transform nameTransform; if (!nameTransforms.TryGetValue(entityTransform, out nameTransform)) { // Get creature Entity creature; Connection.Entities.TryGetValue(entityInfo.Id, out creature); // Create object in list var newNameObj = (GameObject)GameObject.Instantiate(reference, pos, Quaternion.identity); nameTransform = newNameObj.transform; nameTransform.SetParent(me); // Set colored name var color = MabiMath.GetNameColor(entityInfo.Name); var text = nameTransform.GetComponent <Text>(); var name = entityInfo.Name; var displayName = string.Format("<color=#{0:X6}>{1}</color>", color, name); // NPC prefix if (entityInfo.IsConversationNpc) { displayName = "<size=8>NPC</size> " + displayName; } text.text = displayName; // Save for automatic removal nameTransforms.Add(entityTransform, nameTransform); } var nameObject = nameTransform.gameObject; // If entity is visible, activate name object and move it into // position. if (pos.z > 0) { nameTransform.position = pos; if (!nameObject.activeSelf) { nameObject.SetActive(true); } } // If entity is not visible deactivate the name. else if (nameObject.activeSelf) { nameObject.SetActive(false); } } // Check for removed entities var toRemove = new List <Transform>(); foreach (var nameTransformX in nameTransforms) { // Remove name if entity transform became null (destroyed) var entityTransform = nameTransformX.Key; if (entityTransform == null) { var nameTransform = nameTransformX.Value; GameObject.Destroy(nameTransform.gameObject); toRemove.Add(entityTransform); } } // Remove destroyed entity's names from the list if (toRemove.Count != 0) { foreach (var key in toRemove) { nameTransforms.Remove(key); } } }
/// <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); // 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); } } } 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); }
/// <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 targets in skill area Position targetPropPos; var targets = SkillHelper.GetTargetableCreaturesInSkillArea(attacker, SkillLength, SkillWidth, out targetPropPos); // TargetProp var lProp = new Prop(280, attacker.RegionId, targetPropPos.X, targetPropPos.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, targetPropPos).ToLocationId(); var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetAreaId); aAction.Set(AttackerOptions.KnockBackHit1 | AttackerOptions.UseEffect); aAction.PropId = lProp.EntityId; cap.Add(aAction); 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) { CriticalHit.Handle(attacker, 100, ref damage, tAction); } // Handle skills and reductions SkillHelper.HandleMagicDefenseProtection(target, ref damage); SkillHelper.HandleConditions(attacker, target, ref damage); var delayReduction = ManaDeflector.Handle(attacker, target, ref damage, tAction); 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, LightningRodEffect.Attack, targetPropPos.X, targetPropPos.Y); Send.SkillUse(attacker, skill.Info.Id, targetAreaId, 0, 1); skill.Train(1); // Use the Skill attacker.Region.RemoveProp(lProp); }
public override void OnCreation(Dungeon dungeon) { var region = dungeon.Regions.Last(); var bossLocation = dungeon.GetBossRoomCenter(); // Gargoyles region.AddProp(new Prop(29001, bossLocation.RegionId, bossLocation.X, bossLocation.Y, 0)); region.AddProp(new Prop(29002, bossLocation.RegionId, bossLocation.X, bossLocation.Y, 0)); region.AddProp(new Prop(29003, bossLocation.RegionId, bossLocation.X, bossLocation.Y, MabiMath.DegreeToRadian(90))); region.AddProp(new Prop(29004, bossLocation.RegionId, bossLocation.X, bossLocation.Y, MabiMath.DegreeToRadian(90))); region.AddProp(new Prop(29005, bossLocation.RegionId, bossLocation.X, bossLocation.Y, 0)); region.AddProp(new Prop(29006, bossLocation.RegionId, bossLocation.X, bossLocation.Y, 0)); }
/// <summary> /// Spawns brownie for creature's personal shop. /// </summary> /// <param name="creature"></param> protected void SummonBrownie(Creature creature, Item item, string typeName) { var shop = creature.Temp.ActivePersonalShop; if (shop == null) { Send.MsgBox(creature, Localization.Get("The Personal Shop does not exist.")); return; } // Get type var type = ChannelServer.Instance.ScriptManager.GetScriptType(typeName); if (type == null) { Log.Error("SpawnBrownie: Type '{0}' not found.", typeName); Send.MsgBox(creature, Localization.Get("Unable to summon brownie.")); return; } // Check script type var obj = Activator.CreateInstance(type); var npcScript = obj as NpcScript; if (npcScript == null) { Log.Error("SpawnBrownie: Type '{0}' is not an NpcScript.", typeName); Send.MsgBox(creature, Localization.Get("Unable to summon brownie.")); return; } var loc = shop.Prop.GetLocation(); var angle = shop.Prop.Info.Direction + Math.PI / 2; var x = loc.X + 50 * Math.Cos(angle); var y = loc.Y + 50 * Math.Sin(angle); loc.X = (int)x; loc.Y = (int)y; var direction = MabiMath.RadianToByte(shop.Prop.Info.Direction); npcScript.Load(); npcScript.NPC.Name += "@" + Interlocked.Increment(ref _brownieCopyId); npcScript.NPC.SetLocation(loc); npcScript.NPC.Direction = direction; npcScript.NPC.ScriptType = type; shop.Region.AddCreature(npcScript.NPC); shop.SetOverseer(npcScript.NPC, item.EntityId); // Set expiration if it's not set yet if (item.OptionInfo.ExpireTime == 0) { // For some reason the client shows "365 days" more than it should... // reducing them for now. var seconds = (int)(DateTime.Now.AddHours(24).AddDays(-365) - new DateTime(1970, 1, 1)).TotalSeconds; item.OptionInfo.ExpireTime = seconds; Send.ItemUpdate(creature, item); } }
public void AddMessage(string name, string message) { var color = MabiMath.GetNameColor(name); AddMessage(color, name, message); }