summaryrefslogtreecommitdiff
path: root/src/engine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine.cpp')
-rw-r--r--src/engine.cpp500
1 files changed, 500 insertions, 0 deletions
diff --git a/src/engine.cpp b/src/engine.cpp
new file mode 100644
index 00000000..9e0d6b62
--- /dev/null
+++ b/src/engine.cpp
@@ -0,0 +1,500 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 2 of the License, or
+ * any later version.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "engine.h"
+#include "graphics.h"
+#include "gui/gui.h"
+#include "gui/textfield.h"
+#include "gui/minimap.h"
+#include "gui/chargedialog.h"
+#include "gui/itemcontainer.h"
+#include "main.h"
+#include "being.h"
+#include "floor_item.h"
+
+char itemCurrenyQ[10] = "0";
+int map_x, map_y, camera_x, camera_y;
+char npc_text[1000] = "";
+char statsString2[255] = "n/a";
+char skill_points[10] = "";
+bool show_skill_dialog = false;
+bool show_skill_list_dialog = false;
+char npc_button[10] = "Close";
+
+gcn::TextField *chatInput;
+gcn::Label *debugInfo;
+
+ChatBox *chatBox;
+StatusWindow *statusWindow;
+BuyDialog *buyDialog;
+SellDialog *sellDialog;
+BuySellDialog *buySellDialog;
+InventoryWindow *inventoryWindow;
+NpcListDialog *npcListDialog;
+NpcTextDialog *npcTextDialog;
+SkillDialog *skillDialog;
+NewSkillDialog *newSkillWindow;
+StatsWindow *statsWindow;
+Setup* setupWindow;
+Minimap *minimap;
+EquipmentWindow *equipmentWindow;
+ChargeDialog *chargeDialog;
+
+void ChatListener::action(const std::string& eventId)
+{
+ if (eventId == "chatinput") {
+ std::string message = chatInput->getText();
+
+ if (message.length() > 0) {
+ chatBox->chat_send(char_info[0].name, message.c_str());
+ chatInput->setText("");
+ }
+ }
+}
+
+char hairtable[16][4][2] = {
+ // S(x,y) W(x,y) N(x,y) E(x,y)
+ { { 0, 0}, {-1, 2}, {-1, 2}, {0, 2} }, // STAND
+ { { 0, 2}, {-2, 3}, {-1, 2}, {1, 3} }, // WALK 1st frame
+ { { 0, 3}, {-2, 4}, {-1, 3}, {1, 4} }, // WALK 2nd frame
+ { { 0, 1}, {-2, 2}, {-1, 2}, {1, 2} }, // WALK 3rd frame
+ { { 0, 2}, {-2, 3}, {-1, 2}, {1, 3} }, // WALK 4th frame
+ { { 0, 1}, {1, 2}, {-1, 3}, {-2, 2} }, // ATTACK 1st frame
+ { { 0, 1}, {-1, 2}, {-1, 3}, {0, 2} }, // ATTACK 2nd frame
+ { { 0, 2}, {-4, 3}, {0, 4}, {3, 3} }, // ATTACK 3rd frame
+ { { 0, 2}, {-4, 3}, {0, 4}, {3, 3} }, // ATTACK 4th frame
+ { { 0, 0}, {-1, 2}, {-1, 2}, {-1, 2} }, // BOW_ATTACK 1st frame
+ { { 0, 0}, {-1, 2}, {-1, 2}, {-1, 2} }, // BOW_ATTACK 2nd frame
+ { { 0, 0}, {-1, 2}, {-1, 2}, {-1, 2} }, // BOW_ATTACK 3rd frame
+ { { 0, 0}, {-1, 2}, {-1, 2}, {-1, 2} }, // BOW_ATTACK 4th frame
+ { { 0, 4}, {-1, 6}, {-1, 6}, {0, 6} }, // SIT
+ { { 0, 0}, {0, 0}, {0, 0}, {0, 0} }, // ?? HIT
+ { { 0, 16}, {-1, 6}, {-1, 6}, {0, 6} } // DEAD
+};
+
+int get_x_offset(Being *being) {
+ int offset = 0;
+ char direction = being->direction;
+ if (being->action == WALK) {
+ if (direction != NORTH && direction != SOUTH) {
+ offset = being->frame + 1;
+ if (offset == 5) offset = 0;
+ offset *= 8;
+ if (direction == WEST || direction == NW || direction == SW) {
+ offset = -offset;
+ offset += 32;
+ } else offset -= 32;
+ }
+ }
+ return offset;
+}
+
+int get_y_offset(Being *being) {
+ int offset = 0;
+ char direction = being->direction;
+ if (being->action == WALK) {
+ if (direction != EAST && direction != WEST) {
+ offset = being->frame + 1;
+ if (offset == 5) offset = 0;
+ offset *= 8;
+ if (direction == NORTH || direction == NW || direction == NE) {
+ offset = -offset;
+ offset += 32;
+ }
+ else {
+ offset -= 32;
+ }
+ }
+ }
+ return offset;
+}
+
+Engine::Engine()
+{
+ // Initializes GUI
+ chatInput = new TextField();
+ chatInput->setPosition(chatInput->getBorderSize(),
+ screen->h - chatInput->getHeight() -
+ chatInput->getBorderSize());
+ chatInput->setWidth(592 - 2 * chatInput->getBorderSize());
+
+ ChatListener *chatListener = new ChatListener();
+ chatInput->setEventId("chatinput");
+ chatInput->addActionListener(chatListener);
+
+ debugInfo = new gcn::Label();
+
+ chatBox = new ChatBox("./docs/chatlog.txt", 20);
+ chatBox->setSize(592, 100);
+ chatBox->setPosition(0, chatInput->getY() - 1 - chatBox->getHeight());
+
+ guiTop->add(chatBox);
+ guiTop->add(debugInfo);
+ guiTop->add(chatInput);
+
+
+ // Create dialogs
+
+ statusWindow = new StatusWindow();
+ statusWindow->setPosition(screen->w - statusWindow->getWidth() - 5, 5);
+
+ buyDialog = new BuyDialog();
+ buyDialog->setVisible(false);
+
+ sellDialog = new SellDialog();
+ sellDialog->setVisible(false);
+
+ buySellDialog = new BuySellDialog();
+ buySellDialog->setVisible(false);
+
+ inventoryWindow = new InventoryWindow();
+ inventoryWindow->setVisible(false);
+ inventoryWindow->setPosition(screen->w - statusWindow->getWidth() -
+ inventoryWindow->getWidth() - 10, 5);
+
+ npcTextDialog = new NpcTextDialog();
+ npcTextDialog->setVisible(false);
+
+ npcListDialog = new NpcListDialog();
+ npcListDialog->setVisible(false);
+
+ skillDialog = new SkillDialog();
+ skillDialog->setVisible(false);
+
+ newSkillWindow = new NewSkillDialog();
+ newSkillWindow->setVisible(false);
+
+
+ statsWindow = new StatsWindow();
+ statsWindow->setVisible(false);
+ statsWindow->setPosition(
+ screen->w - 5 - statsWindow->getWidth(),
+ statusWindow->getHeight() + 20);
+
+ setupWindow = new Setup();
+ setupWindow->setVisible(false);
+
+ minimap = new Minimap();
+
+ equipmentWindow = new EquipmentWindow();
+ equipmentWindow->setVisible(false);
+
+ chargeDialog = new ChargeDialog();
+ chargeDialog->setVisible(true);
+ chargeDialog->setPosition(
+ screen->w - 5 - chargeDialog->getWidth(),
+ screen->h - chargeDialog->getHeight() - 15);
+
+ // Give focus to the chat input
+ chatInput->requestFocus();
+
+ // Load the sprite sets
+ ResourceManager *resman = ResourceManager::getInstance();
+ Image *npcbmp = resman->getImage(
+ "core/graphics/sprites/npcs.png");
+ Image *emotionbmp = resman->getImage(
+ "core/graphics/sprites/emotions.png");
+ Image *monsterbitmap = resman->getImage(
+ "core/graphics/sprites/monsters.png");
+ Image *weaponbitmap = resman->getImage(
+ "core/graphics/sprites/weapons.png");
+ Image *itembitmap = resman->getImage(
+ "core/graphics/sprites/items.png");
+
+ if (!npcbmp) error("Unable to load npcs.png");
+ if (!emotionbmp) error("Unable to load emotions.png");
+ if (!monsterbitmap) error("Unable to load monsters.png");
+ if (!weaponbitmap) error("Unable to load weapons.png");
+ if (!itembitmap) error("Unable to load items.png");
+
+ npcset = new Spriteset(npcbmp, 50, 80);
+ emotionset = new Spriteset(emotionbmp, 19, 19);
+ monsterset = new Spriteset(monsterbitmap, 60, 60);
+ weaponset = new Spriteset(weaponbitmap, 160, 120);
+ itemset = new Spriteset(itembitmap, 20, 20);
+}
+
+Engine::~Engine()
+{
+ delete chatBox;
+ delete statusWindow;
+ delete buyDialog;
+ delete sellDialog;
+ delete buySellDialog;
+ delete npcListDialog;
+ delete npcTextDialog;
+ delete skillDialog;
+ delete statsWindow;
+ delete setupWindow;
+ delete minimap;
+ delete equipmentWindow;
+ delete newSkillWindow;
+
+ delete monsterset;
+ delete npcset;
+ delete emotionset;
+ delete weaponset;
+ delete itemset;
+}
+
+void Engine::draw()
+{
+ // Get the current mouse position
+ int mouseX, mouseY;
+ SDL_GetMouseState(&mouseX, &mouseY);
+
+ map_x = (player_node->x - 13) * 32 + get_x_offset(player_node);
+ map_y = (player_node->y - 9) * 32 + get_y_offset(player_node);
+
+ camera_x = map_x / 32;
+ camera_y = map_y / 32;
+
+ int offset_x = map_x & 31;
+ int offset_y = map_y & 31;
+
+ sort();
+
+ frame++;
+
+ // Draw tiles below nodes
+ if (tiledMap) {
+ tiledMap->draw(guiGraphics, map_x, map_y, 0);
+ tiledMap->draw(guiGraphics, map_x, map_y, 1);
+ }
+
+ // Draw items
+ std::list<FloorItem*>::iterator floorItemIterator = floorItems.begin();
+ while (floorItemIterator != floorItems.end())
+ {
+ FloorItem *floorItem = (*floorItemIterator);
+ unsigned short x = floorItem->x;
+ unsigned short y = floorItem->y;
+ int sx = x - camera_x;
+ int sy = y - camera_y;
+ int absx = sx * 32 - offset_x;
+ int absy = sy * 32 - offset_y;
+ if (floorItem->id >= 501 && floorItem->id <= 1202) {
+ itemset->spriteset[floorItem->id - 501]->draw(screen,
+ absx,
+ absy);
+ }
+
+ floorItemIterator++;
+ }
+
+ // Draw nodes
+ std::list<Being*>::iterator beingIterator = beings.begin();
+ while (beingIterator != beings.end())
+ {
+ Being *being = (*beingIterator);
+
+ unsigned short x = being->x;
+ unsigned short y = being->y;
+ unsigned char dir = being->direction / 2;
+ int sx = x - camera_x;
+ int sy = y - camera_y;
+
+#ifdef DEBUG
+ guiGraphics->setColor(gcn::Color(0, 0, 255));
+ guiGraphics->drawRectangle(gcn::Rectangle(sx * 32, sy * 32, 32, 32));
+#endif
+
+ if ((being->job >= 100) && (being->job <= 110)) { // Draw a NPC
+ npcset->spriteset[4 * (being->job - 100) + dir]->draw(screen,
+ sx * 32 - 8 - offset_x,
+ sy * 32 - 52 - offset_y);
+ }
+ else if (being->job < 10) { // Draw a player
+ being->text_x = sx * 32 + get_x_offset(being) - offset_x;
+ being->text_y = sy * 32 + get_y_offset(being) - offset_y;
+
+ if (being->action == SIT || being->action == DEAD) {
+ being->frame = 0;
+ }
+
+ int pf = being->frame + being->action;
+
+ if (being->action == ATTACK) {
+ pf += 4 * being->weapon;
+ }
+
+ playerset->spriteset[4 * pf + dir]->draw(screen,
+ being->text_x - 64, being->text_y - 80);
+ if (being->weapon != 0 && being->action == ATTACK) {
+ weaponset->spriteset[4 * being->frame + dir]->draw(screen,
+ being->text_x - 64, being->text_y - 80);
+ }
+
+ if (being->hair_color <= 10) {
+ int hf = being->hair_color - 1 + 10 * (dir + 4 *
+ (being->hair_style - 1));
+
+ hairset->spriteset[hf]->draw(screen,
+ being->text_x - 2 + 2 * hairtable[pf][dir][0],
+ being->text_y - 50 + 2 * hairtable[pf][dir][1]);
+ }
+
+ if (being->emotion != 0) {
+ emotionset->spriteset[being->emotion - 1]->draw(screen,
+ sx * 32 - 5 + get_x_offset(being) - offset_x,
+ sy * 32 - 45 + get_y_offset(being) - offset_y);
+ being->emotion_time--;
+ if (being->emotion_time == 0) {
+ being->emotion = 0;
+ }
+ }
+ if (being->action != STAND && being->action != SIT
+ && being->action != DEAD) {
+ being->frame =
+ (get_elapsed_time(being->walk_time) * 4) / (being->speed);
+
+ if (being->frame >= 4) {
+ being->frame = 0;
+ being->action = STAND;
+ if (being->id == player_node->id) {
+ walk_status = 0;
+ }
+ }
+ }
+ }
+ else if (being->job == 45) { // Draw a warp
+ } else { // Draw a monster
+ if (being->frame >= 4)
+ being->frame = 3;
+
+ being->text_x = sx * 32 - 42 + get_x_offset(being) - offset_x;
+ being->text_y = sy * 32 - 65 + get_y_offset(being) - offset_y;
+
+ int sprnum = dir + 4 * (being->job - 1002);
+ int mf = being->frame + being->action;
+
+ if (being->action == MONSTER_DEAD) {
+ monsterset->spriteset[sprnum + 12 * MONSTER_DEAD]->draw(screen,
+ being->text_x + 30, being->text_y + 40);
+ }
+ else {
+ monsterset->spriteset[sprnum + 12 * mf]->draw(screen,
+ being->text_x + 30, being->text_y + 40);
+ }
+
+ if (being->action != STAND) {
+ being->frame =
+ (get_elapsed_time(being->walk_time) * 4) / (being->speed);
+
+ if (being->frame >= 4) {
+ if (being->action != MONSTER_DEAD && being->hasPath()) {
+ being->nextStep();
+ }
+ }
+ }
+ }
+
+ if (being->action == MONSTER_DEAD && being->frame >= 20) {
+ delete being;
+ beingIterator = beings.erase(beingIterator);
+ }
+ else {
+ beingIterator++;
+ }
+
+ // nodes are ordered so if the next being y is > then the
+ // last drawed for fringe layer, draw the missing lines
+ }
+
+ // Draw tiles below nodes
+ if (tiledMap) {
+ tiledMap->draw(guiGraphics, map_x, map_y, 2);
+ }
+
+ // Find a path from the player to the mouse, and draw it. This is for debug
+ // purposes.
+ if (displayPathToMouse)
+ {
+ PATH_NODE *debugPath = tiledMap->findPath(
+ player_node->x, player_node->y,
+ mouseX / 32 + camera_x, mouseY / 32 + camera_y);
+
+ while (debugPath)
+ {
+ int squareX = (debugPath->x - camera_x) * 32 - offset_x + 12;
+ int squareY = (debugPath->y - camera_y) * 32 - offset_y + 12;
+ guiGraphics->setColor(gcn::Color(255, 0, 0));
+ guiGraphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8));
+
+ MetaTile *tile = tiledMap->getMetaTile(debugPath->x, debugPath->y);
+
+ std::stringstream cost;
+ cost << tile->Gcost;
+ guiGraphics->drawText(cost.str(), squareX + 4, squareY + 12,
+ gcn::Graphics::CENTER);
+
+ // Move to the next node
+ PATH_NODE *temp = debugPath->next;
+ delete debugPath;
+ debugPath = temp;
+ }
+ }
+
+ // Draw player speech
+ beingIterator = beings.begin();
+ while (beingIterator != beings.end()) {
+ Being *being = (*beingIterator);
+
+ if (being->speech != NULL) {
+ //if (being->speech_color == makecol(255, 255, 255)) {
+ // guiGraphics->drawText(being->speech,
+ // being->text_x + 16, being->text_y - 60,
+ // gcn::Graphics::CENTER);
+ //}
+ //else {
+ guiGraphics->drawText(being->speech,
+ being->text_x + 60, being->text_y - 60,
+ gcn::Graphics::CENTER);
+ //}
+
+ being->speech_time--;
+ if (being->speech_time == 0) {
+ free(being->speech);
+ being->speech = NULL;
+ }
+ }
+
+ beingIterator++;
+ }
+
+ if (statsWindow->isVisible()) {
+ statsWindow->update();
+ }
+ if (statusWindow->isVisible()) {
+ statusWindow->update();
+ }
+
+ gui->draw();
+
+ std::stringstream debugStream;
+ debugStream << "[" << fps << " fps] " <<
+ (mouseX / 32 + camera_x) << ", " << (mouseY / 32 + camera_y) << " "
+ << player_node->weapon;
+ debugInfo->setCaption(debugStream.str());
+ debugInfo->adjustSize();
+}