package src.Monster
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.display.Sprite;
import gs.TweenLite;
import gs.easing.*;
import src.Interface.MonsterInformation.MonsterInformation;
import src.Monster.LifeBar.LifeBar;
import src.Tower.Bullet.Bullet;
import src.Tower.DefaultTowersProperties.DefaultTowerProperties;
import src.Main;
import src.Tile.FindPathResult;
import src.Tile.Tile;
import src.Tile.LayerMonsters.LayerMonsters;
/**
* ...
* @author www.flashist.ru — Flash уроки, обхоры новых сайтов и интересных игр.
*/
public class Monster extends Sprite
{
// Начальные переменные со свойствами монстра и массивом контрольных точек
public var monsterProperties:MonsterProperties;
public var findPath:FindPathResult;
// Переменные направления движения
private var dirX:Number = 0;
private var dirY:Number = 0;
// Переменные номеров ячеек начальной и конечной точек
private var startY:Number = 0;
private var startX:Number = 0;
private var finY:Number = 0;
private var finX:Number = 0;
// Переменные координат в пикселях конечной точки
private var pixelStartY:Number = 0;
private var pixelStartX:Number = 0;
private var pixelFinY:Number = 0;
private var pixelFinX:Number = 0;
// Переменная текущей контрольной точки
private var currentPoint:Number = 0;
// Переменная для хранения поворота
private var rotationTween:TweenLite;
// Переменная, которая будет запоминать, был ли уже послан запрос на удаление монстра, или нет
private var isRemoved:Boolean = false;
// Клип, с информацией о монстре
private var info_mc:MonsterInformation;
// Переменная, которая будет запоминать, существует сейчас окошко с информацией о монстре или нет
private var isInfo:Boolean = false;
// Клип для отображения полоски жизней монстра
private var lifeBar_mc:LifeBar;
public function Monster(monsterProperties:MonsterProperties, findPath:FindPathResult)
{
this.monsterProperties = monsterProperties;
this.findPath = findPath;
this.comeToPoint();
this.addEnterFrameEvent();
//this.setOnMouseOverEvent();
this.addClickEvent();
this.lifeBar_mc = Main.root.world_mc.tile.layerOthers_mc.attachMonsterLifeBar(this);
}
// Функция, которая будет запускаться, когда монстр прибудет в конечную точку назначения
private function comeToPoint()
{
// Проверяем, если мы сейчас находимся на последней точке назначения, то удаляем монстра
if (this.currentPoint == this.findPath.resultLength - 1)
{
this.toEnd();
return;
}
/*trace("this.y " + this.y + " | pointY = "+this.findPath.result_array[this.currentPoint][0] * Tile.tileHeight);
trace("this.x " + this.x + " | pointX = " + this.findPath.result_array[this.currentPoint][1] * Tile.tileWidth);
trace("");*/
// Находим координаты конечной и начальной точек в пикселях. Прибавление ширины и высоты нужно для
// того, чтобы монстр двигался по центрам ячеек
this.pixelStartY = this.findPath.result_array[this.currentPoint][0] * Tile.tileHeight + Tile.tileHeight * 0.5;
this.pixelStartX = this.findPath.result_array[this.currentPoint][1] * Tile.tileWidth + Tile.tileWidth * 0.5;
this.pixelFinY = this.findPath.result_array[this.currentPoint + 1][0] * Tile.tileHeight + Tile.tileHeight * 0.5;
this.pixelFinX = this.findPath.result_array[this.currentPoint + 1][1] * Tile.tileWidth + Tile.tileWidth * 0.5;
// Устанавливаем монстра в точку, в которую он только что прибыл (нужно, если он стоит не в ней)
this.y = this.pixelStartY;
this.x = this.pixelStartX;
// Находим направление движения
this.findDirection(this.pixelStartY, this.pixelStartX, this.pixelFinY, this.pixelFinX);
// Увеличиваем значение «счёта точек», чтобы в следующий раз монстр шёл к следующей точке
this.currentPoint++;
}
// Находим направление движения
private function findDirection( startY:Number, startX:Number, finY:Number, finX:Number)
{
// Переменная, для хранения угла поворота, который найдётся ниже
var newRotation:Number = 0;
var delenie:Number = this.rotation / 90;
// Находим направление по горизонтали
// Если стартовая точка меньше конечной, то движение будет вправо
if (startX < finX)
{
this.dirX = 1;
newRotation = 0;
// Если стартовая точка больше конечной, то движение будет влево
}else if (startX > finX)
{
this.dirX = -1;
newRotation = 180;
// Если стартовая точка равна конечной, то движения по горизонтали нет
}else
{
this.dirX = 0;
}
// Находим направление по вертикали
// Если стартовая точка больше конечной, то движение будет вниз
if (startY < finY)
{
this.dirY = 1;
newRotation = 90;
// Если стартовая точка меньше конечной, то движение будет вверх
}else if (startY > finY)
{
this.dirY = -1;
newRotation = 270;
// Если стартовая точка равна конечной, то движения по вертикали нет
}else
{
this.dirY = 0;
}
/*// Этот блок необходим, чтобы монстры нормально поворачивались
var delta:Number = newRotation - this.rotation;
if (delta > 180)
{
newRotation = newRotation - 360;
}else if (delta > 180)
{
newRotation = newRotation + 360;
}
// Поворачиваем монстра в сторону движения к новой точке, если нужно
//trace("this.rotation " + this.rotation);
//trace("newRotation " + newRotation);
this.rotationTween = new TweenLite(this, 0.2, { rotation: newRotation } );*/
}
// Функция движения
public function toMove()
{
//trace("speedMultiplier " + speedMultiplier);
this.x += this.monsterProperties.currentSpeed * this.dirX;
this.y += this.monsterProperties.currentSpeed * this.dirY;
/*this.x = Math.round(this.x);
this.y = Math.round(this.y);*/
// Проверяем дошли ли мы или не перескочили ли мы нужную точку. Если перескочили, то ставим монстра в конечную точку
// и запускаем функцию, для начала движения к следующей точке
// Если мы движемся вправо, и дошли ушли правее
if (this.dirX > 0)
{
if (this.x >= this.pixelFinX)
{
//trace("Ушло правее");
this.comeToPoint();
return;
}
// Если мы движемся влево, и дошли ушли левее
}else if (this.dirX < 0)
{
if (this.x <= this.pixelFinX)
{
//trace("Ушло левее");
this.comeToPoint();
return;
}
// Если мы движемся вниз, и дошли ушли ниже
}else if (this.dirY > 0)
{
if (this.y >= this.pixelFinY)
{
//trace("Ушло ниже");
this.comeToPoint();
return;
}
// Если мы движемся вверх, и дошли ушли выше
}else if (this.dirY < 0)
{
if (this.y <= this.pixelFinY)
{
//trace("Ушло выше");
this.comeToPoint();
return;
}
}
}
// Функции добавления и удаления слушателей EnterFrame
public function addEnterFrameEvent()
{
this.addEventListener(Event.ENTER_FRAME, this.onEnterFrame);
}
public function removeEnterFrameEvent()
{
this.removeEventListener(Event.ENTER_FRAME, this.onEnterFrame);
}
public function onEnterFrame(event:Event)
{
this.toMove();
this.checkCurrentSpeed();
}
// Функция удаления клипа
public function toEnd()
{
// Если монстру уже посылалась команда на удаление, то прекращаем выполнение функции
if (this.isRemoved)
{
return;
}
// Ставим для переменной isRemoved значение true
this.setIsRemoved(true);
// Если информация о монстре показывается, то убираем её
if(this.isInfo){
this.info_mc.toEnd();
}
// Удаляем полоску с отображением жизней
this.lifeBar_mc.toEnd();
// Удаляем монстра из слоя с монстрами
LayerMonsters(this.parent).removeCurrentMonster(this);
// Удаляем слушатели всех событий
this.removeEnterFrameEvent();
this.removeClickEvent();
/*this.removeOnMouseOverEvent();
this.removeOnMouseOutEvent();*/
}
// Фукнция, которая будет вызываться при попадании пули
public function toBulletShot(bullet:Bullet):Number
{
var prop:DefaultTowerProperties = bullet.tower.startProp.defaultProps;
var countResistences:Number = 0;
var valueResistences:Number = 0;
// Смотрим, какие типы урона несёт в себе пуля
if (prop.isFire)
{
valueResistences += this.monsterProperties.fire;
countResistences ++;
}
if (prop.isCold)
{
valueResistences += this.monsterProperties.cold;
countResistences ++;
}
if (prop.isPoison)
{
valueResistences += this.monsterProperties.pison;
countResistences ++;
}
if (prop.isElectric)
{
valueResistences += this.monsterProperties.electric;
countResistences ++;
}
//trace("valueResistences " + valueResistences);
//trace("countResistences " + countResistences);
var realResistence:Number = 0;
if (countResistences != 0)
{
// Находим среднюю величину сопротивлений
realResistence = valueResistences / countResistences;
}
// Находим реальный урон, который нанесёт пуля монстру
var realDamage:Number = bullet.damage - realResistence;
// Если урон минус сопротивления меньше или равен нулю, то возвращаем ноль
if (realDamage <= 0)
{
return 0;
}
//trace("realDamage " + realDamage);
// Если урон больше нуля, то отнимаем его от жизней монстра. Запоминаем возвращаемое значение
// в переменную опыта, которую передадим в башню. Так как возвращаемое значение будет со знаком
// минус, мы его ещё раз минусуем.
var expForTower:Number = -1 * this.toPlusCurrentLife( -realDamage);
// Возвращаем найденное значение
return expForTower;
}
// Функция изменения количества жизней
public function toPlusCurrentLife(plus:Number):Number
{
if (this.isRemoved)
{
return 0;
}
// Изменяем количество текущих жизней и округляем их до 2 знаков после запятой
this.monsterProperties.currentLife = this.monsterProperties.currentLife + plus;
// Проверяем, если жизни меньше или равны нулю, то удаляем монстра
if (this.monsterProperties.currentLife <= 0)
{
// Если урон был больше, чем есть жизней у монстра, то отнимаем из возвращаемого значения
// количество жизней меньше нуля.
plus -= this.monsterProperties.currentLife;
this.monsterProperties.currentLife = 0;
this.toEnd();
}
// Меняем длину полоски жизней
this.lifeBar_mc.changeLifeBar();
// Если информация о монстре показывается сейчас, то изменяем в ней информацию о жизнях
if (this.isInfo)
{
this.info_mc.setLifeText();
}
// Возвращаем значение, на которое уменьшили или увеличили жизни монстра
return plus;
}
// Функция установки флага isRemoved, запоминающего, был ли уже послан запрос на удаление монстра
public function setIsRemoved(flag:Boolean)
{
this.isRemoved = flag;
}
// Функция подключения клипа с информацией
public function attachInfo()
{
// Если подсказка уже есть, то прекращаем выполнение функции
if (this.isInfo)
{
return
}
// Устанавливаем флаг на то, что подсказка создана
this.isInfo = true;
// Создаём подсказку
this.info_mc = Main.root.toAttachMonsterInformation();
this.info_mc.x = this.x;
this.info_mc.y = this.y;
this.info_mc.toSetMonster(this);
this.info_mc.toStart();
this.info_mc.addOnEnterFrame();
}
public function removeInfo()
{
// Если подсказки ещё нет, или её уже удалили, то прекращаем выполнение функции
if (!this.isInfo)
{
return
}
// Ставим флаг на то, что мы удаляем подсказку
this.isInfo = false;
// запускаем функцию удаления подсказки
this.info_mc.toEnd();
}
// Функции подключения и удаления слушателя onClick и сам слушатель
public function addClickEvent()
{
this.addEventListener(MouseEvent.MOUSE_DOWN, this.onClick);
}
public function removeClickEvent()
{
this.removeEventListener(MouseEvent.MOUSE_DOWN, this.onClick);
}
public function onClick(event:MouseEvent)
{
// Проверяем, создана подсказка или нет
if (this.isInfo)
{
this.removeInfo();
}else
{
this.attachInfo();
}
}
// Функции установки и удаления слушателя события onMouseOver
public function setOnMouseOverEvent()
{
this.addEventListener(MouseEvent.MOUSE_OVER, this.onMouseOver);
}
public function removeOnMouseOverEvent()
{
this.removeEventListener(MouseEvent.MOUSE_OVER, this.onMouseOver);
}
// Слушатель onMouseOver
public function onMouseOver(event:MouseEvent)
{
this.attachInfo();
// Удаляем слушателя события MouseOver
this.removeOnMouseOverEvent();
// Начинаем «слушать» событие ухода мышки с монстра
this.setOnMouseOutEvent();
}
// Функции установки и удаления слушателя события onMouseOut
public function setOnMouseOutEvent()
{
this.addEventListener(MouseEvent.MOUSE_OUT, this.onMouseOut);
}
public function removeOnMouseOutEvent()
{
this.removeEventListener(MouseEvent.MOUSE_OUT, this.onMouseOut);
}
// Слушатель onMouseOut
public function onMouseOut(event:MouseEvent)
{
this.removeInfo();
// Удаляем слушателя события MouseOut
this.removeOnMouseOutEvent();
// Начинаем «слушать» событие захода мышки на монстра
this.setOnMouseOverEvent();
}
// Функция сокращения текущей скорости, в зависимости от всех «влияющих» на скорость факторов
public function checkCurrentSpeed()
{
var tileY:Number = Math.floor(this.y / Tile.tileHeight );
var tileX:Number = Math.floor(this.x / Tile.tileWidth );
var speedMultiplier:Number = Tile.getTile(tileY, tileX);
// Устанавливаем новое значение currentSpeed
this.monsterProperties.currentSpeed = this.monsterProperties.maxSpeed / speedMultiplier;
// Если скорость меньше 1, то делаем скорость равной 1, это нужно для того, чтобы монстры
// не «застывали» на месте, так как при округлении до целочисленных, они не будут сдвигаться
// с места.
/*if (this.monsterProperties.currentSpeed < 1)
{
this.monsterProperties.currentSpeed = 1;
}*/
}
}
}