|
|
@@ -1,17 +1,22 @@
|
|
|
-#include "GameState.h"
|
|
|
#include "piaf/Archive.h"
|
|
|
#include "input/Input.h"
|
|
|
#include "render/Text.h"
|
|
|
+#include "engine/StateMachine.h"
|
|
|
#include "Graphics.h"
|
|
|
#include "Logger.h"
|
|
|
|
|
|
+#include "GameState.h"
|
|
|
#include "Player.h"
|
|
|
+#include "Ghost.h"
|
|
|
+#include "AIPlayer.h"
|
|
|
#include "static_data.h"
|
|
|
|
|
|
#include <luwra.hpp>
|
|
|
|
|
|
using Pacman::GameState;
|
|
|
using Pacman::Player;
|
|
|
+using Pacman::AIPlayer;
|
|
|
+using Pacman::Ghost;
|
|
|
using Pacman::ButtonInput;
|
|
|
using Pacman::MoveIntent;
|
|
|
using WalrusRPG::PIAF::Archive;
|
|
|
@@ -90,37 +95,126 @@ const uint8_t gums_model[] = {
|
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
|
};
|
|
|
|
|
|
-GameState::GameState() : level(1), map(28, 31, map_data, nullptr, map_texture), cam(-(320-28*8)/2,4),
|
|
|
- p1(4,4), p2(204,228), L(luaL_newstate()), blinky_ready(false)
|
|
|
-{
|
|
|
- p1.up = new ButtonInput(K_A);
|
|
|
- p1.down = new ButtonInput(K_B);
|
|
|
- p1.left = new ButtonInput(K_L);
|
|
|
- p1.right = new ButtonInput(K_R);
|
|
|
+struct Corner{int x; int y;};
|
|
|
|
|
|
- p2.up = new ButtonInput(K_UP);
|
|
|
- p2.down = new ButtonInput(K_DOWN);
|
|
|
- p2.left = new ButtonInput(K_LEFT);
|
|
|
- p2.right = new ButtonInput(K_RIGHT);
|
|
|
|
|
|
+GameState::GameState() : level(1), map(28, 31, map_data, nullptr, map_texture), cam(-(320-28*8),4),
|
|
|
+ p1(nullptr),
|
|
|
+ p2(nullptr),
|
|
|
+ L(luaL_newstate())
|
|
|
+{
|
|
|
luaL_openlibs(L);
|
|
|
- load_ghost_script("data/blinky.lua", "blinky", blinky_ready);
|
|
|
+
|
|
|
+ // Creating game state functions/mechanisms
|
|
|
+
|
|
|
+ lua_CFunction cfun_collide = LUWRA_WRAP(GameState::does_collide_long);
|
|
|
+ lua_CFunction cfun_getgum = LUWRA_WRAP(GameState::LH_get_gum_by_pixel_pos);
|
|
|
+ lua_CFunction cfun_ispixelsolid = LUWRA_WRAP(GameState::LH_is_pixel_solid);
|
|
|
+ lua_CFunction cfun_getTile = LUWRA_WRAP(GameState::LH_get_tile);
|
|
|
+
|
|
|
+
|
|
|
+ lua_createtable(L, 0,0);
|
|
|
+ luwra::Table gameState(L, -1);
|
|
|
+ gameState.set("data", this);
|
|
|
+ gameState.set("map", map);
|
|
|
+ gameState.set("collide", cfun_collide);
|
|
|
+ gameState.set("get_tile", cfun_getTile);
|
|
|
+
|
|
|
+ luwra::setGlobal(L, "gamestate", gameState);
|
|
|
+ p1 = new AIPlayer(4,4, *this, "data/p2.lua", "p2");
|
|
|
+ p2 = new AIPlayer(200,228, *this, "data/p2.lua", "p2");
|
|
|
+ blinky = new Ghost(68, 84, *this, "data/blinky.lua", "blinky");
|
|
|
+ inky = new Ghost(140, 84, *this, "data/inky.lua", "inky");
|
|
|
+ pinky = new Ghost(68, 132, *this, "data/pinky.lua", "pinky");
|
|
|
+ clyde = new Ghost(140, 132, *this, "data/clyde.lua", "clyde");
|
|
|
+ updateLuaState();
|
|
|
+ p1->initAI();
|
|
|
+ p2->initAI();
|
|
|
+ blinky->initAI();
|
|
|
+ inky->initAI();
|
|
|
+ pinky->initAI();
|
|
|
+ clyde->initAI();
|
|
|
+
|
|
|
set_gums();
|
|
|
}
|
|
|
|
|
|
GameState::~GameState()
|
|
|
{
|
|
|
lua_close(L);
|
|
|
+ delete p1;
|
|
|
+ delete p2;
|
|
|
+ delete blinky;
|
|
|
+ delete pinky;
|
|
|
+ delete inky;
|
|
|
+ delete clyde;
|
|
|
+}
|
|
|
+
|
|
|
+luwra::Table GameState::registerEntity(Entity* e){
|
|
|
+ lua_createtable(L,0,0);
|
|
|
+ luwra::Table table(L, -1);
|
|
|
+ table.set("x", e->x);
|
|
|
+ table.set("y", e->y);
|
|
|
+ table.set("vx", e->vx);
|
|
|
+ table.set("vy", e->vy);
|
|
|
+
|
|
|
+ return table;
|
|
|
+}
|
|
|
+void GameState::updateLuaState() {
|
|
|
+ lua_getglobal(L, "gamestate");
|
|
|
+ luwra::Table gameState(L, -1);
|
|
|
+ gameState.set("p1", registerEntity(p1));
|
|
|
+ gameState.set("p2", registerEntity(p2));
|
|
|
+ gameState.set("blinky", registerEntity(blinky));
|
|
|
+ gameState.set("inky", registerEntity(inky));
|
|
|
+ gameState.set("pinky", registerEntity(pinky));
|
|
|
+ gameState.set("clyde", registerEntity(clyde));
|
|
|
}
|
|
|
|
|
|
void GameState::update(unsigned dt)
|
|
|
{
|
|
|
+ int stack_size = lua_gettop(L);
|
|
|
+
|
|
|
+ if(remaining_pills == 0 || (p1->dead && p2->dead))
|
|
|
+ {
|
|
|
+ if(Input::key_down(Key::K_START))
|
|
|
+ {
|
|
|
+ dead = true;
|
|
|
+
|
|
|
+ // Uncomment and commend dead if you want to make it run endlessly
|
|
|
+ /*level++;
|
|
|
+ set_gums();
|
|
|
+ p1->reset();
|
|
|
+ p2->reset();
|
|
|
+ blinky->reset();
|
|
|
+ inky->reset();
|
|
|
+ pinky->reset();
|
|
|
+ clyde->reset();
|
|
|
+
|
|
|
+ p1->initAI();
|
|
|
+ p2->initAI();
|
|
|
+ blinky->initAI();
|
|
|
+ inky->initAI();
|
|
|
+ pinky->initAI();
|
|
|
+ clyde->initAI();
|
|
|
+ */
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
map.update(dt);
|
|
|
- p1.update(dt);
|
|
|
- p2.update(dt);
|
|
|
- move_player(p1);
|
|
|
- move_player(p2);
|
|
|
- update_ghost("blinky", blinky_ready);
|
|
|
+ p1->update(dt);
|
|
|
+ p1->points += 10*collect_gums({p1->x, p1->y, 16, 16});
|
|
|
+ p2->update(dt);
|
|
|
+ p2->points += 10*collect_gums({p2->x, p2->y, 16, 16});
|
|
|
+ blinky->update(dt);
|
|
|
+ inky->update(dt);
|
|
|
+ pinky->update(dt);
|
|
|
+ clyde->update(dt);
|
|
|
+ updateLuaState();
|
|
|
+
|
|
|
+ lua_pop(L, stack_size);
|
|
|
+ //move_player(p1);
|
|
|
+ //move_player(p2);
|
|
|
}
|
|
|
|
|
|
void GameState::render(unsigned dt)
|
|
|
@@ -146,28 +240,101 @@ void GameState::render(unsigned dt)
|
|
|
// render_player(j1);
|
|
|
// render_player(j2);
|
|
|
|
|
|
- p1.render(dt, cam);
|
|
|
- p2.render(dt, cam);
|
|
|
+ p1->render(dt, cam);
|
|
|
+ p2->render(dt, cam);
|
|
|
+ blinky->render(dt, cam, Red);
|
|
|
+ inky->render(dt, cam, Cyan);
|
|
|
+ pinky->render(dt, cam, Pixel(255, 153, 204));
|
|
|
+ clyde->render(dt, cam, Pixel(255, 153, 51));
|
|
|
// Borders
|
|
|
|
|
|
put_rectangle({0, 0, 0u-cam.get_x(), 320}, DarkGray);
|
|
|
- put_rectangle({320+cam.get_x(), 0, 0u-cam.get_x(), 320}, DarkGray);
|
|
|
put_rectangle({-cam.get_x(),0, 1, 240}, White);
|
|
|
- put_rectangle({320+cam.get_x(),0, 1, 240}, White);
|
|
|
+
|
|
|
+ Text::print_format(0,0,"Level %6d", level);
|
|
|
+ Text::print_format(0,8,"P1 : %07d", p1->points);
|
|
|
+ Text::print_format(0,16,"P2 : %07d", p2->points);
|
|
|
+
|
|
|
+ if(remaining_pills == 0 || (p1->dead && p2->dead)) {
|
|
|
+ if(p1->points > p2-> points) {
|
|
|
+ Text::print_format(0, 48, "P1 Won");
|
|
|
+ } else if(p2->points > p1-> points) {
|
|
|
+ Text::print_format(0, 48, "P2 Won");
|
|
|
+ } else {
|
|
|
+ Text::print_format(0, 48, "It's a draw.");
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
void GameState::set_gums()
|
|
|
{
|
|
|
+ remaining_pills = 0;
|
|
|
for (int y = 0; y < 31; ++y)
|
|
|
{
|
|
|
for (int x = 0; x < 28; ++x)
|
|
|
{
|
|
|
+ if(gums[y][x]) remaining_pills++;
|
|
|
gums[y][x] = (Pacgum)gums_model[28*y + x];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+int GameState::collect_gums(Rect r)
|
|
|
+{
|
|
|
+ Corner left{r.x, r.y+(int)(r.height-1)/2};
|
|
|
+ Corner right{r.x+(int)(r.width-1), r.y+(int)(r.height-1)/2};
|
|
|
+ Corner top{r.x+(int)(r.width-1)/2, r.y};
|
|
|
+ Corner bottom{r.x+(int)(r.width-1)/2, r.y+(int)(r.height-1)};
|
|
|
+ Corner center{r.x+(int)(r.width-1)/2, r.y+(int)(r.height-1)/2};
|
|
|
+ int pt = 0;
|
|
|
+ if(LH_get_gum_by_pixel_pos(left.x/8, left.y/8) != 0){
|
|
|
+ gums[left.y/8][left.x/8] = NOTHING;
|
|
|
+ pt++;
|
|
|
+ }
|
|
|
+ if(LH_get_gum_by_pixel_pos(right.x/8, right.y/8) != 0){
|
|
|
+ if(LH_get_gum_by_pixel_pos(right.x/8, right.y/8) == 2) {
|
|
|
+ blinky->make_weak();
|
|
|
+ inky->make_weak();
|
|
|
+ pinky->make_weak();
|
|
|
+ clyde->make_weak();
|
|
|
+ }
|
|
|
+ gums[right.y/8][right.x/8] = NOTHING;
|
|
|
+ pt++;
|
|
|
+ }
|
|
|
+ if(LH_get_gum_by_pixel_pos(top.x/8, top.y/8) != 0){
|
|
|
+ if(LH_get_gum_by_pixel_pos(top.x/8, top.y/8) == 2) {
|
|
|
+ blinky->make_weak();
|
|
|
+ inky->make_weak();
|
|
|
+ pinky->make_weak();
|
|
|
+ clyde->make_weak();
|
|
|
+ }
|
|
|
+ gums[top.y/8][top.x/8] = NOTHING;
|
|
|
+ pt++;
|
|
|
+ }
|
|
|
+ if(LH_get_gum_by_pixel_pos(bottom.x/8, bottom.y/8) != 0){
|
|
|
+ if(LH_get_gum_by_pixel_pos(bottom.x/8, bottom.y/8) == 2) {
|
|
|
+ blinky->make_weak();
|
|
|
+ inky->make_weak();
|
|
|
+ pinky->make_weak();
|
|
|
+ clyde->make_weak();
|
|
|
+ }
|
|
|
+ gums[bottom.y/8][bottom.x/8] = NOTHING;
|
|
|
+ pt++;
|
|
|
+ }
|
|
|
+ if(LH_get_gum_by_pixel_pos(center.x/8, center.y/8) != 0){
|
|
|
+ if(LH_get_gum_by_pixel_pos(center.x/8, center.y/8) == 2) {
|
|
|
+ blinky->make_weak();
|
|
|
+ inky->make_weak();
|
|
|
+ pinky->make_weak();
|
|
|
+ clyde->make_weak();
|
|
|
+ }
|
|
|
+ gums[center.y/8][center.x/8] = NOTHING;
|
|
|
+ pt++;
|
|
|
+ }
|
|
|
+ return pt;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* Does a corner-based collision check for a small Rect.
|
|
|
* Assumes that said Rect as big or smaller than a tile
|
|
|
@@ -177,8 +344,6 @@ void GameState::set_gums()
|
|
|
*/
|
|
|
bool GameState::does_collide_a_wall(Rect r)
|
|
|
{
|
|
|
- struct Corner{int x; int y;};
|
|
|
-
|
|
|
Corner top_left{r.x, r.y};
|
|
|
Corner top_right{(r.x+(int)r.width-1), r.y};
|
|
|
Corner bottom_left{r.x, (r.y+(int)r.height-1)};
|
|
|
@@ -189,80 +354,66 @@ bool GameState::does_collide_a_wall(Rect r)
|
|
|
|| (is_inside_map(bottom_left.x, bottom_left.y) && (map.is_tile_solid(bottom_left.x/8, bottom_left.y/8) != 0));
|
|
|
}
|
|
|
|
|
|
-void GameState::move_player(Player &p)
|
|
|
+bool GameState::does_collide_long(int x, int y, int width, int height)
|
|
|
+{
|
|
|
+ return does_collide_a_wall({x, y, (unsigned)width, (unsigned)height});
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void GameState::move_player(Entity *p)
|
|
|
{
|
|
|
- if(p.intent == UP) {
|
|
|
- if(!does_collide_a_wall({p.x+4, p.y+4-1, 8, 8})){
|
|
|
- p.vy = -1;
|
|
|
- p.vx = 0;
|
|
|
+ if(p->intent == UP) {
|
|
|
+ if(!does_collide_a_wall({p->x+4, p->y+4-1, 8, 8})){
|
|
|
+ p->vy = -1;
|
|
|
+ p->vx = 0;
|
|
|
}
|
|
|
}
|
|
|
- if(p.intent == DOWN) {
|
|
|
- if(!does_collide_a_wall({p.x+4, p.y+4+1, 8, 8})){
|
|
|
- p.vy = 1;
|
|
|
- p.vx = 0;
|
|
|
+ if(p->intent == DOWN) {
|
|
|
+ if(!does_collide_a_wall({p->x+4, p->y+4+1, 8, 8})){
|
|
|
+ p->vy = 1;
|
|
|
+ p->vx = 0;
|
|
|
}
|
|
|
}
|
|
|
- if(p.intent == LEFT) {
|
|
|
- if(!does_collide_a_wall({p.x+4-1, p.y+4, 8, 8})){
|
|
|
- p.vx = -1;
|
|
|
- p.vy = 0;
|
|
|
+ if(p->intent == LEFT) {
|
|
|
+ if(!does_collide_a_wall({p->x+4-1, p->y+4, 8, 8})){
|
|
|
+ p->vx = -1;
|
|
|
+ p->vy = 0;
|
|
|
}
|
|
|
}
|
|
|
- if(p.intent == RIGHT) {
|
|
|
- if(!does_collide_a_wall({p.x+4+1, p.y+4, 8, 8})){
|
|
|
- p.vx = 1;
|
|
|
- p.vy = 0;
|
|
|
+ if(p->intent == RIGHT) {
|
|
|
+ if(!does_collide_a_wall({p->x+4+1, p->y+4, 8, 8})){
|
|
|
+ p->vx = 1;
|
|
|
+ p->vy = 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if(does_collide_a_wall({p.x+4+p.vx, p.y+4+p.vy, 8, 8})){
|
|
|
- p.vy = 0;
|
|
|
- p.vx = 0;
|
|
|
+ if(does_collide_a_wall({p->x+4+p->vx, p->y+4+p->vy, 8, 8})){
|
|
|
+ p->vy = 0;
|
|
|
+ p->vx = 0;
|
|
|
}
|
|
|
|
|
|
- p.x += p.vx;
|
|
|
- p.y += p.vy;
|
|
|
+ p->x += p->vx;
|
|
|
+ p->y += p->vy;
|
|
|
|
|
|
- if(p.x < -8)
|
|
|
- p.x = 224-8;
|
|
|
- if(p.x+16 > 232)
|
|
|
- p.x = 0;
|
|
|
+ if(p->x < -8)
|
|
|
+ p->x = 224-8;
|
|
|
+ if(p->x+16 > 232)
|
|
|
+ p->x = 0;
|
|
|
}
|
|
|
|
|
|
-void GameState::load_ghost_script(const char* filename, const char* ghost_name, bool& ready_flag)
|
|
|
+bool GameState::is_there_collision(Entity* a, Entity* b)
|
|
|
{
|
|
|
- int result = luaL_loadfile (L, filename) || lua_pcall(L,0,0,0);
|
|
|
- if(result != LUA_OK)
|
|
|
- {
|
|
|
- Logger::error("Lua : Error while loading %s : %s", filename, lua_tostring(L, -1));
|
|
|
- lua_pop(L, 1);
|
|
|
- ready_flag = false;
|
|
|
- }
|
|
|
- else{
|
|
|
- Logger::log("Lua : %s correctly loaded.", filename);
|
|
|
- try {
|
|
|
- lua_getglobal(L, ghost_name);
|
|
|
- luwra::Table t = luwra::read<luwra::Table>(L, -1);
|
|
|
- t.get<luwra::NativeFunction<void>>("init")(t);
|
|
|
- ready_flag = true;
|
|
|
- } catch(std::exception e)
|
|
|
- {
|
|
|
- Logger::error("Error while loading %s : %s", ghost_name);
|
|
|
- ready_flag = false;
|
|
|
- }
|
|
|
- }
|
|
|
+ if ((a->x + 16 < b->x) || (a->x > b->x+16))
|
|
|
+ return false;
|
|
|
+ else if ((a->y + 16 < b->y) || (a->y > b->y + 16))
|
|
|
+ return false;
|
|
|
+ else return true;
|
|
|
}
|
|
|
|
|
|
-void GameState::update_ghost(const char* ghost_name, bool& ready_flag) {
|
|
|
- if(ready_flag) {
|
|
|
- try{
|
|
|
- lua_getglobal(L, ghost_name);
|
|
|
- luwra::Table t = luwra::read<luwra::Table>(L, -1);
|
|
|
- t.get<luwra::NativeFunction<void>>("update")(t);
|
|
|
- }catch(std::exception e) {
|
|
|
- Logger::error("Error while executing %s: %s", ghost_name, e.what());
|
|
|
- ready_flag = false;
|
|
|
- }
|
|
|
- }
|
|
|
+luwra::Table GameState::LH_get_tile(int tx, int ty){
|
|
|
+ lua_createtable(L,0,0);
|
|
|
+ luwra::Table t(L, -1);
|
|
|
+ t.set("is_solid", LH_is_tile_solid(tx, ty)!=0);
|
|
|
+ t.set("gum", LH_does_tile_has_gum_solid(tx, ty));
|
|
|
+ return t;
|
|
|
}
|