Initial commit
This commit is contained in:
219
engines/crab/level/level_ai.cpp
Normal file
219
engines/crab/level/level_ai.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on the CRAB engine
|
||||
*
|
||||
* Copyright (c) Arvind Raja Yadav
|
||||
*
|
||||
* Licensed under MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "crab/level/level.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace TMX;
|
||||
using namespace pyrodactyl::stat;
|
||||
using namespace pyrodactyl::anim;
|
||||
using namespace pyrodactyl::level;
|
||||
using namespace pyrodactyl::image;
|
||||
using namespace pyrodactyl::people;
|
||||
using namespace pyrodactyl::input;
|
||||
using namespace pyrodactyl::event;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Let the level tick along and notify if we go into an exit
|
||||
//------------------------------------------------------------------------
|
||||
LevelResult Level::internalEvents(Info &info, Common::Array<EventResult> &result, Common::Array<EventSeqInfo> &endSeq, bool eventInProgress) {
|
||||
LevelResult lResult;
|
||||
|
||||
// input.internalEvents();
|
||||
calcTrigCollide(info);
|
||||
|
||||
if (_terrain.collideWithExit(_objects[_playerIndex].boundRect(), lResult)) {
|
||||
if (playerInCombat(info)) {
|
||||
_insideExit = true;
|
||||
} else if (_insideExit == false) {
|
||||
lResult._type = LR_LEVEL;
|
||||
return lResult;
|
||||
}
|
||||
} else {
|
||||
_insideExit = false;
|
||||
|
||||
if (playerInCombat(info))
|
||||
_showmap._current = false;
|
||||
else
|
||||
_showmap._current = _showmap._normal;
|
||||
}
|
||||
|
||||
if (eventInProgress)
|
||||
playerStop();
|
||||
else
|
||||
think(info, result, endSeq, lResult._val);
|
||||
|
||||
if (lResult._val != "")
|
||||
info.lastPerson(lResult._val);
|
||||
else if (collidingWithObject(info, lResult._val))
|
||||
info.lastPerson(lResult._val);
|
||||
else
|
||||
info.lastPerson("");
|
||||
|
||||
return lResult;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Let the AI think and animate the level
|
||||
//------------------------------------------------------------------------
|
||||
void Level::think(pyrodactyl::event::Info &info, Common::Array<pyrodactyl::event::EventResult> &result,
|
||||
Common::Array<pyrodactyl::event::EventSeqInfo> &endSeq, Common::String &id) {
|
||||
uint index = 0;
|
||||
for (auto i = _objects.begin(); i != _objects.end(); ++i, ++index) {
|
||||
// Only bother if the sprite is visible
|
||||
if (i->visible()) {
|
||||
// TODO: Find a place where this should be initialized... (SZ)
|
||||
if (i->_pathing._grid == nullptr)
|
||||
i->_pathing.initialize(&_pathfindingGrid);
|
||||
|
||||
// If a sprite is dead, nothing else matters
|
||||
if (info.state(i->id()) == PST_DYING) {
|
||||
if (i->lastFrame()) {
|
||||
info.statSet(i->id(), STAT_HEALTH, 0);
|
||||
info.state(i->id(), PST_KO);
|
||||
i->effectImg(false);
|
||||
i->inputStop();
|
||||
}
|
||||
} else if (info.state(i->id()) != PST_KO) {
|
||||
Rect boundRect = i->boundRect();
|
||||
|
||||
i->_pathing.setPosition(Vector2f((float)(boundRect.x + boundRect.w / 2), (float)boundRect.y + boundRect.h / 2));
|
||||
i->_pathing.update(0);
|
||||
|
||||
// For the AI sprites
|
||||
if (index != _playerIndex) {
|
||||
switch (info.state(i->id())) {
|
||||
case PST_FIGHT: {
|
||||
// Only attack if the player is alive
|
||||
if (info.state(_objects[_playerIndex].id()) < PST_KO)
|
||||
i->attack(info, _objects[_playerIndex], _scDefault);
|
||||
} break;
|
||||
case PST_FLEE:
|
||||
i->flee(info, _terrain._areaExit, _scDefault);
|
||||
break;
|
||||
case PST_NORMAL:
|
||||
if (i->takingDamage(_objects[_playerIndex], _scDefault)) {
|
||||
if (_firstHit) {
|
||||
battleAlert(info);
|
||||
_firstHit = false;
|
||||
}
|
||||
}
|
||||
/*else
|
||||
TraversePath(*i);*/
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Only do this if the player is alive
|
||||
if (info.state(_objects[_playerIndex].id()) < PST_KO)
|
||||
_objects[_playerIndex].exchangeDamage(info, *i, _scDefault);
|
||||
} else {
|
||||
// For the player sprite
|
||||
boundRect = i->boundRect();
|
||||
|
||||
i->_pathing.setPosition(Vector2f((float)(boundRect.x + boundRect.w / 2), (float)boundRect.y + boundRect.h / 2));
|
||||
i->_pathing.update(0);
|
||||
|
||||
i->moveToDestPathfinding(info, _scDefault);
|
||||
}
|
||||
|
||||
i->internalEvents(info, playerId(), result, endSeq);
|
||||
moveObject(info, *i);
|
||||
}
|
||||
|
||||
i->animate(info);
|
||||
}
|
||||
}
|
||||
|
||||
// Background sprites don't move
|
||||
for (auto &i : _background)
|
||||
i.animate(PST_NORMAL);
|
||||
|
||||
// Flier sprites fly across the screen from left to right or vice versa
|
||||
// The movement is semi-random
|
||||
for (auto &i : _fly) {
|
||||
i.flyAround(_camera, _scDefault);
|
||||
i.animate(PST_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Once a player provokes any sprite, call this function
|
||||
//------------------------------------------------------------------------
|
||||
void Level::battleAlert(pyrodactyl::event::Info &info) {
|
||||
uint index = 0;
|
||||
for (auto i = _objects.begin(); i != _objects.end(); ++i, ++index) {
|
||||
if (index != _playerIndex && i->visible() && info.state(i->id()) != PST_KO) {
|
||||
switch (info.type(i->id())) {
|
||||
case PE_NEUTRAL:
|
||||
case PE_HOSTILE:
|
||||
info.state(i->id(), PST_FIGHT);
|
||||
break;
|
||||
case PE_COWARD:
|
||||
info.state(i->id(), PST_FLEE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Move a sprite according to its velocity
|
||||
//------------------------------------------------------------------------
|
||||
void Level::moveObject(pyrodactyl::event::Info &info, pyrodactyl::anim::Sprite &s) {
|
||||
// Update x,y coordinates according to velocity
|
||||
s.move(_scDefault);
|
||||
|
||||
// First check collision with objects and forbidden areas inside a level
|
||||
if (collidingWithLevel(info, s))
|
||||
s.resolveCollide();
|
||||
|
||||
// Finally see if we are inside the overall level bounds
|
||||
if (!_terrain.insideWalk(s.boundRect()))
|
||||
s.resolveInside(_terrain.areaWalk());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: If any other object is trying to kill you, you are in combat
|
||||
//------------------------------------------------------------------------
|
||||
bool Level::playerInCombat(pyrodactyl::event::Info &info) {
|
||||
uint index = 0;
|
||||
for (auto i = _objects.begin(); i != _objects.end(); ++i, ++index)
|
||||
if (index != _playerIndex && info.state(i->id()) == PST_FIGHT && i->visible())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
Reference in New Issue
Block a user