summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ManaWorld.vcproj1
-rw-r--r--src/astar.cpp326
-rw-r--r--src/astar.h25
-rw-r--r--src/being.cpp210
-rw-r--r--src/being.h80
-rw-r--r--src/game.cpp663
-rw-r--r--src/game.h92
-rw-r--r--src/graphic/graphic.cpp256
-rw-r--r--src/graphic/graphic.h50
-rw-r--r--src/graphic/super_eagle.cpp450
-rw-r--r--src/graphic/super_eagle.h44
-rw-r--r--src/gui/char_select.cpp221
-rw-r--r--src/gui/char_select.h41
-rw-r--r--src/gui/char_server.cpp141
-rw-r--r--src/gui/char_server.h41
-rw-r--r--src/gui/chat.cpp303
-rw-r--r--src/gui/chat.h150
-rw-r--r--src/gui/gui.cpp1471
-rw-r--r--src/gui/gui.h121
-rw-r--r--src/gui/inventory.cpp249
-rw-r--r--src/gui/inventory.h80
-rw-r--r--src/gui/login.cpp139
-rw-r--r--src/gui/login.h43
-rw-r--r--src/gui/skill.cpp56
-rw-r--r--src/gui/skill.h40
-rw-r--r--src/log.cpp189
-rw-r--r--src/log.h45
-rw-r--r--src/main.cpp156
-rw-r--r--src/main.h86
-rw-r--r--src/map.cpp120
-rw-r--r--src/map.h89
-rw-r--r--src/net/network.cpp177
-rw-r--r--src/net/network.h87
-rw-r--r--src/net/protocol.cpp264
-rw-r--r--src/net/protocol.h57
-rw-r--r--src/net/win2linux.h54
-rw-r--r--src/net/win2mac.cpp42
-rw-r--r--src/net/win2mac.h16
-rw-r--r--src/sound/sound.cpp269
-rw-r--r--src/sound/sound.h83
40 files changed, 7027 insertions, 0 deletions
diff --git a/ManaWorld.vcproj b/ManaWorld.vcproj
index effc0451..75ff47d1 100644
--- a/ManaWorld.vcproj
+++ b/ManaWorld.vcproj
@@ -84,6 +84,7 @@
OutputFile="The Mana World.exe"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
diff --git a/src/astar.cpp b/src/astar.cpp
new file mode 100644
index 00000000..5fff9687
--- /dev/null
+++ b/src/astar.cpp
@@ -0,0 +1,326 @@
+#include "astar.h"
+#include "being.h"
+
+const int numberPeople = 1;
+ int onClosedList = 10;
+ const int notfinished = 0;// path-related constants
+
+ //Create needed arrays
+ //char get_path_walk [MAP_WIDTH][MAP_HEIGHT];
+ int openList[MAP_WIDTH*MAP_HEIGHT+2]; //1 dimensional array holding ID# of open list items
+ int whichList[MAP_WIDTH+1][MAP_HEIGHT+1]; //2 dimensional array used to record
+// whether a cell is on the open list or on the closed list.
+ int openX[MAP_WIDTH*MAP_HEIGHT+2]; //1d array stores the x location of an item on the open list
+ int openY[MAP_WIDTH*MAP_HEIGHT+2]; //1d array stores the y location of an item on the open list
+ int parentX[MAP_WIDTH+1][MAP_HEIGHT+1]; //2d array to store parent of each cell (x)
+ int parentY[MAP_WIDTH+1][MAP_HEIGHT+1]; //2d array to store parent of each cell (y)
+ int F_cost[MAP_WIDTH*MAP_HEIGHT+2]; //1d array to store F cost of a cell on the open list
+ int G_cost[MAP_WIDTH+1][MAP_HEIGHT+1]; //2d array to store G_cost cost for each cell.
+ int H_cost[MAP_WIDTH*MAP_HEIGHT+2]; //1d array to store H cost of a cell on the open list
+ int pathLength; //stores length of the FOUND path for critter
+ int pathLocation; //stores current position along the chosen path for critter
+ int* path_bank ;
+
+ //Path reading variables
+ int pathStatus;
+ int xPath;
+ int yPath;
+
+/** Initialize pathfinder */
+void pathfinder_init() {
+ path_bank = (int*)malloc(4);
+}
+
+/** Exit pathfinder */
+void pathfinder_exit() {
+ free(path_bank);
+}
+
+/** Find path */
+PATH_NODE *find_path(int pathfinderID, int s_x, int s_y, int e_x, int e_y) {
+ int onOpenList=0, parentXval=0, parentYval=0,
+ a=0, b=0, m=0, u=0, v=0, temp=0, corner=0, numberOfOpenListItems=0,
+ addedGCost=0, tempG = 0, path = 0, x=0, y=0,
+ tempx, pathX, pathY, cellPosition,
+ newOpenListItemID=0;
+
+ // If starting location and target are in the same location...
+ if (s_x==e_x && s_y==e_y && pathLocation>0)return NULL;
+ else if (s_x==e_x && s_y==e_y && pathLocation==0)return NULL;
+
+ // If dest tile is NOT_WALKABLE, return that it's a NOT_FOUND path.
+ if(get_path_walk(e_x, e_y)==NOT_WALKABLE) {
+ xPath = s_x;
+ yPath = s_y;
+ return NULL;
+ }
+
+ // Reset some variables that need to be cleared
+ for(x=0;x<MAP_WIDTH;x++) {
+ for(y=0;y<MAP_HEIGHT;y++)
+ whichList [x][y] = 0;
+ }
+ onClosedList = 2; //changing the values of onOpenList and onClosed list is faster than redimming whichList() array
+ onOpenList = 1;
+ pathLength = NOT_STARTED;
+ pathLocation = NOT_STARTED;
+ G_cost[s_x][s_y] = 0; //reset starting square's G_cost value to 0
+
+ // Add the starting location to the open list of tiles to be checked.
+ numberOfOpenListItems = 1;
+ openList[1] = 1;//assign it as the top (and currently only) item in the open list, which is maintained as a binary heap (explained below)
+ openX[1] = s_x ; openY[1] = s_y;
+
+ // Do the following until a path is FOUND or deemed NOT_FOUND.
+ do {
+
+ // If the open list is not empty, take the first cell off of the list.
+ // This is the lowest F cost cell on the open list.
+ if (numberOfOpenListItems != 0) {
+
+ // Pop the first item off the open list.
+ parentXval = openX[openList[1]];
+ parentYval = openY[openList[1]]; //record cell coordinates of the item
+ whichList[parentXval][parentYval] = onClosedList;//add the item to the closed list
+
+ // Open List = Binary Heap: Delete this item from the open list, which
+ numberOfOpenListItems = numberOfOpenListItems - 1;//reduce number of open list items by 1
+
+ // Delete the top item in binary heap and reorder the heap, with the lowest F cost item rising to the top.
+ openList[1] = openList[numberOfOpenListItems+1];//move the last item in the heap up to slot #1
+ v = 1;
+
+ // Repeat the following until the new item in slot #1 sinks to its proper spot in the heap.
+ do {
+ u = v;
+ if (2*u+1 <= numberOfOpenListItems) { //if both children exist
+ //Check if the F cost of the parent is greater than each child.
+ //Select the lowest of the two children.
+ if(F_cost[openList[u]] >= F_cost[openList[2*u]])v = 2*u;
+ if(F_cost[openList[v]] >= F_cost[openList[2*u+1]])v = 2*u+1;
+ } else {
+ if (2*u <= numberOfOpenListItems) { //if only child #1 exists
+ //Check if the F cost of the parent is greater than child #1
+ if (F_cost[openList[u]] >= F_cost[openList[2*u]])v = 2*u;
+ }
+ }
+
+ if (u!=v) { // if parent's F is > one of its children, swap them
+ temp = openList[u];
+ openList[u] = openList[v];
+ openList[v] = temp;
+ } else break; //otherwise, exit loop
+ } while (u!=v); //reorder the binary heap
+
+
+// Check the adjacent squares. (Its "children" -- these path children
+// are similar, conceptually, to the binary heap children mentioned
+// above, but don't confuse them. They are different. Path children
+// are portrayed in Demo 1 with grey pointers pointing toward
+// their parents.) Add these adjacent child squares to the open list
+// for later consideration if appropriate (see various if statements
+// below).
+
+ for(b=parentYval-1;b<=parentYval+1;b++) {
+ for(a=parentXval-1;a<=parentXval+1;a++) {
+ // If not off the map (do this first to avoid array out-of-bounds errors)
+ if(a!=-1 && b!=-1 && a!=MAP_WIDTH && b!=MAP_HEIGHT) {
+ // If not already on the closed list (items on the closed list have
+ // already been considered and can now be ignored).
+ if(whichList[a][b]!=onClosedList) {
+ // If not a wall/obstacle square.
+ if (get_path_walk(a, b)!=NOT_WALKABLE) {
+ // Don't cut across corners
+ corner = WALKABLE;
+ if(a==parentXval-1) {
+ if(b==parentYval-1) {
+ if(get_path_walk(parentXval-1, parentYval)==NOT_WALKABLE || get_path_walk(parentXval, parentYval-1)==NOT_WALKABLE) // cera slash
+ corner = NOT_WALKABLE;
+ } else if (b==parentYval+1) {
+ if(get_path_walk(parentXval, parentYval+1)==NOT_WALKABLE || get_path_walk(parentXval-1, parentYval)==NOT_WALKABLE)
+ corner = NOT_WALKABLE;
+ }
+ } else if(a==parentXval+1) {
+ if(b==parentYval-1) {
+ if(get_path_walk(parentXval, parentYval-1)==NOT_WALKABLE || get_path_walk(parentXval+1, parentYval)==NOT_WALKABLE)
+ corner = NOT_WALKABLE;
+ } else if(b==parentYval+1) {
+ if(get_path_walk(parentXval+1, parentYval)==NOT_WALKABLE || get_path_walk(parentXval, parentYval+1)==NOT_WALKABLE)
+ corner = NOT_WALKABLE;
+ }
+ }
+
+ if(corner==WALKABLE) {
+ // If not already on the open list, add it to the open list.
+ if (whichList[a][b]!=onOpenList) {
+ // Create a new open list item in the binary heap.
+ newOpenListItemID = newOpenListItemID + 1; //each new item has a unique ID #
+ m = numberOfOpenListItems+1;
+ openList[m] = newOpenListItemID;//place the new open list item (actually, its ID#) at the bottom of the heap
+ openX[newOpenListItemID] = a;
+ openY[newOpenListItemID] = b;//record the x and y coordinates of the new item
+
+ //Figure out its G_cost cost
+ if (abs(a-parentXval) == 1 && abs(b-parentYval) == 1)addedGCost = 14;//cost of going to diagonal squares
+ else addedGCost = 10;//cost of going to non-diagonal squares
+ G_cost[a][b] = G_cost[parentXval][parentYval] + addedGCost;
+
+ //Figure out its H and F costs and parent
+ H_cost[openList[m]] = 10*(abs(a - e_x) + abs(b - e_y));
+ F_cost[openList[m]] = G_cost[a][b] + H_cost[openList[m]];
+ parentX[a][b] = parentXval ; parentY[a][b] = parentYval;
+
+ //Move the new open list item to the proper place in the binary heap.
+ //Starting at the bottom, successively compare to parent items,
+ //swapping as needed until the item finds its place in the heap
+ //or bubbles all the way to the top (if it has the lowest F cost).
+ while(m!=1) { // While item hasn't bubbled to the top (m=1)
+ //Check if child's F cost is < parent's F cost. If so, swap them.
+ if(F_cost[openList[m]]<=F_cost[openList[m/2]]) {
+ temp = openList[m/2];
+ openList[m/2] = openList[m];
+ openList[m] = temp;
+ m = m/2;
+ } else break;
+ }
+
+ numberOfOpenListItems = numberOfOpenListItems+1;//add one to the number of items in the heap
+ //Change whichList to show that the new item is on the open list.
+ whichList[a][b] = onOpenList;
+ } else { // If whichList(a,b) = onOpenList
+ // If adjacent cell is already on the open list, check to see if this
+ // path to that cell from the starting location is a better one.
+ // If so, change the parent of the cell and its G_cost and F costs.
+ //Figure out the G_cost cost of this possible new path
+ if(abs(a-parentXval)==1 && abs(b-parentYval)==1)addedGCost = 14;//cost of going to diagonal tiles
+ else addedGCost = 10;//cost of going to non-diagonal tiles
+
+ tempG = G_cost[parentXval][parentYval] + addedGCost;
+
+ // If this path is shorter (G_cost cost is lower) then change
+ // the parent cell, G_cost cost and F cost.
+ if(tempG<G_cost[a][b]) { //if G_cost cost is less,
+ parentX[a][b] = parentXval; //change the square's parent
+ parentY[a][b] = parentYval;
+ G_cost[a][b] = tempG;//change the G_cost cost
+
+ // Because changing the G_cost cost also changes the F cost, if
+ // the item is on the open list we need to change the item's
+ // recorded F cost and its position on the open list to make
+ // sure that we maintain a properly ordered open list.
+
+ for(int x=1;x<=numberOfOpenListItems;x++) { //look for the item in the heap
+ if(openX[openList[x]]==a && openY[openList[x]]==b) { //item FOUND
+ F_cost[openList[x]] = G_cost[a][b] + H_cost[openList[x]];//change the F cost
+ //See if changing the F score bubbles the item up from it's current location in the heap
+ m = x;
+ while(m!=1) { //While item hasn't bubbled to the top (m=1)
+ //Check if child is < parent. If so, swap them.
+ if(F_cost[openList[m]]<F_cost[openList[m/2]]) {
+ temp = openList[m/2];
+ openList[m/2] = openList[m];
+ openList[m] = temp;
+ m = m/2;
+ } else break;
+ }
+ break; //exit for x = loop
+ } // If openX(openList(x)) = a
+ } // For x = 1 To numberOfOpenListItems
+ } // If tempG < G_cost(a,b)
+ } // else If whichList(a,b) = onOpenList
+ } // If not cutting a corner
+ } // If not a wall/obstacle square.
+ } // If not already on the closed list
+ } // If not off the map
+ } // for (a = parentXval-1; a <= parentXval+1; a++){
+ } // for (b = parentYval-1; b <= parentYval+1; b++){
+ } else {// if (numberOfOpenListItems != 0)
+ // If open list is empty then there is no path.
+ path = NOT_FOUND;
+ break;
+ }
+ //If target is added to open list then path has been FOUND.
+ if (whichList[e_x][e_y]==onOpenList) {
+ path = FOUND;
+ break;
+ }
+
+ } while (path!=FOUND && path!=NOT_FOUND);//Do until path is FOUND or deemed NOT_FOUND
+
+ // Save the path if it exists.
+ if (path == FOUND) {
+
+ // Working backwards from the target to the starting location by checking
+ // each cell's parent, figure out the length of the path.
+ pathX = e_x; pathY = e_y;
+ do {
+ //Look up the parent of the current cell.
+ tempx = parentX[pathX][pathY];
+ pathY = parentY[pathX][pathY];
+ pathX = tempx;
+
+ //Figure out the path length
+ pathLength = pathLength + 1;
+ } while (pathX != s_x || pathY != s_y);
+
+ // Resize the data bank to the right size in bytes
+ path_bank = (int*) realloc (path_bank, pathLength*8);
+
+ // Now copy the path information over to the databank. Since we are
+ // working backwards from the target to the start location, we copy
+ // the information to the data bank in reverse order. The result is
+ // a properly ordered set of path data, from the first step to the last.
+ pathX = e_x ; pathY = e_y;
+ cellPosition = pathLength*2;//start at the end
+ do {
+ cellPosition = cellPosition - 2;//work backwards 2 integers
+ path_bank [cellPosition] = pathX;
+ path_bank [cellPosition+1] = pathY;
+ // Look up the parent of the current cell.
+ tempx = parentX[pathX][pathY];
+ pathY = parentY[pathX][pathY];
+ pathX = tempx;
+ // If we have reached the starting square, exit the loop.
+ } while(pathX!=s_x || pathY!=s_y);
+
+ char stringa[80];
+ sprintf(stringa,"%i %i",s_x,s_y);
+
+ PATH_NODE *ret = NULL, *temp = NULL;
+ pathLocation = 1;
+ ret = create_path_node(s_x,s_y);
+ temp = ret;
+ //alert(stringa,"","","","",0,0);
+ while(pathLocation<pathLength) {
+ sprintf(stringa,"%i %i",path_bank[pathLocation*2-2], path_bank[pathLocation*2-1]);
+ //alert(stringa,"","","","",0,0);
+ temp->next = create_path_node(path_bank[pathLocation*2-2], path_bank[pathLocation*2-1]);
+ if(temp->next==NULL)ok("Error", "Unable to create path node");
+ temp = temp->next;
+ pathLocation++;
+ }
+ if(temp!=NULL)temp->next = create_path_node(e_x, e_y);
+ else ok("Error", "Null reference");
+ return ret;
+
+ }
+ return NULL; // Path not found
+}
+
+
+
+/** Read the path data */
+void ReadPath(int pathfinderID) {
+ //If a path exists, read the path data
+ // from the pathbank.
+ pathLocation = 1; //set pathLocation to 1st step
+ while (pathLocation<pathLength) {
+ int a = path_bank [pathLocation*2-2];
+ int b = path_bank [pathLocation*2-1];
+ pathLocation = pathLocation + 1;
+ whichList[a][b] = 3;//draw dotted path
+ }
+}
+
+
+
diff --git a/src/astar.h b/src/astar.h
new file mode 100644
index 00000000..4a9fa045
--- /dev/null
+++ b/src/astar.h
@@ -0,0 +1,25 @@
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#include <allegro.h>
+
+#include "map.h"
+#include "being.h"
+
+#define NOT_STARTED 0
+#define FOUND 1
+#define NOT_FOUND 2
+
+extern char walkability [MAP_WIDTH][MAP_HEIGHT];
+extern int whichList[MAP_WIDTH+1][MAP_HEIGHT+1];
+extern int G_cost[MAP_WIDTH+1][MAP_HEIGHT+1];
+
+void ReadPath(int pathfinderID,int currentX,int currentY, int pixelsPerFrame);
+int ReadPathX(int pathfinderID,int pathLocation);
+int ReadPathY(int pathfinderID,int pathLocation);
+void RenderScreen (bool stepByStep=false);
+PATH_NODE *find_path(int pathfinderID,int startingX, int startingY, int targetX, int targetY);
+void ReadPath(int pathfinderID);
+
+
diff --git a/src/being.cpp b/src/being.cpp
new file mode 100644
index 00000000..ca527882
--- /dev/null
+++ b/src/being.cpp
@@ -0,0 +1,210 @@
+/**
+
+ 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
+
+*/
+
+#include <stdio.h>
+#include <memory.h>
+#ifndef MACOSX
+ #include <malloc.h>
+#endif
+
+#ifdef LINUXPPC
+ #include <malloc.h>
+#endif
+
+#include "astar.h"
+#include "being.h"
+
+NODE *player_node = NULL;
+NODE *head = NULL; // First node of the list
+unsigned int count = 0; // Number of beings in the list
+
+/** Create a path node */
+PATH_NODE *create_path_node(unsigned short x, unsigned short y) {
+ PATH_NODE *ret = (PATH_NODE *)malloc(sizeof(PATH_NODE));
+ ret->x = x;
+ ret->y = y;
+ ret->next = NULL;
+ return ret;
+}
+
+/** Return a* path */
+PATH_NODE *calculate_path(unsigned short src_x, unsigned short src_y, unsigned short dest_x, unsigned short dest_y) {
+ return find_path(1, src_x, src_y, dest_x, dest_y);
+}
+
+/** Returns the first node of the list */
+NODE *get_head() {
+ return head;
+}
+
+/** Creates a empty node */
+NODE *create_node() {
+ NODE *node = (NODE *)malloc(sizeof(NODE));
+ node->id = 0;
+ node->job = 0;
+ memset(node->coordinates, 0, 3);
+ node->next = NULL;
+ node->action = 0;
+ node->frame = 0;
+ node->path = NULL;
+ node->speech = NULL;
+ node->speech_time = 0;
+ node->speech_color = makecol(255,255,255);
+ node->tick_time = 0;
+ node->speed = 150;
+ node->emotion = 0;
+ node->emotion_time = 0;
+ node->text_x = node->text_y = 0;
+ return node;
+}
+
+/** Returns number of beings in the list */
+unsigned int get_count() {
+ return count;
+}
+
+/** Removes all beings from the list */
+void empty() {
+ NODE *node = head;
+ NODE *next;
+ while(node) {
+ next = node->next;
+ free(node);
+ node = next;
+ }
+ count = 0;
+ head = NULL;
+}
+
+/** Add a node to the list */
+void add_node(NODE *node) {
+ NODE *temp = head;
+ if(temp) {
+ while(temp->next)
+ temp = temp->next;
+ temp->next = node;
+ } else head = node;
+ count++;
+}
+
+/** Remove a node */
+void remove_node(unsigned int id) {
+ unsigned int temp;
+ NODE *node_old, *node_new;
+ node_old = head;
+ node_new = NULL;
+ while(node_old) {
+ temp = get_id(node_old);
+ if(temp==id) {
+ if(node_new==NULL) {
+ head = node_old->next;
+ free(node_old);
+ count--;
+ return;
+ } else {
+ node_new->next = node_old->next;
+ free(node_old);
+ count--;
+ return;
+ }
+ } else {
+ node_new = node_old;
+ node_old = node_old->next;
+ }
+ }
+}
+
+/** Returns the id of a being in the list */
+unsigned int get_id(NODE *node) {
+ return node->id;
+}
+
+/** Find a NPC id based on its coordinates */
+unsigned int find_npc(unsigned short x, unsigned short y) {
+ NODE *node = head;
+ while(node) {
+ if((node->job>=46)&&(node->job<=125)) { // Check if is a NPC (only low job ids)
+ if((get_x(node->coordinates)==x)&&(get_y(node->coordinates)==y))
+ return node->id;
+ else node = node->next;
+ } else node = node->next;
+ }
+ return 0;
+}
+
+/** Find a MONSTER id based on its coordinates */
+unsigned int find_monster(unsigned short x, unsigned short y) {
+ NODE *node = head;
+ while(node) {
+ //if((node->job>=46)&&(node->job<=125)) { // Check if is a NPC (only low job ids)
+ if((get_x(node->coordinates)==x)&&(get_y(node->coordinates)==y))
+ return node->id;
+ else node = node->next;
+ //} else node = node->next;
+ }
+ return 0;
+}
+
+/** Return a specific id node */
+NODE *find_node(unsigned int id) {
+ NODE *node = head;
+ while(node)
+ if(node->id==id)
+ return node;
+ else node = node->next;
+ return NULL;
+}
+
+/** Sort beings in vertical order using bubble sort */
+void sort() {
+ NODE *p, *q, *r, *s, *temp;
+ s = NULL;
+
+ while(s!=head->next) {
+ r = p = head;
+ q = p->next;
+
+ while(p!=s) {
+ if(get_y(p->coordinates)>get_y(q->coordinates)) {
+ if(p==head) {
+ temp = q->next;
+ q->next = p;
+ p->next = temp;
+ head = q;
+ r = q;
+ } else {
+ temp = q->next;
+ q->next = p;
+ p->next = temp;
+ r->next = q;
+ r = q;
+ }
+ } else {
+ r = p;
+ p = p->next;
+ }
+ q = p->next;
+ if(q==s)s = p;
+ }
+ }
+}
diff --git a/src/being.h b/src/being.h
new file mode 100644
index 00000000..d1dcdb31
--- /dev/null
+++ b/src/being.h
@@ -0,0 +1,80 @@
+/**
+
+ 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
+
+*/
+
+#ifndef _BEING_H
+#define _BEING_H
+
+#include "./Net/protocol.h"
+
+#define ACTION_NODE 0
+#define PLAYER_NODE 1
+#define NPC_NODE 2
+#define MONSTER_NODE 3
+
+struct PATH_NODE {
+ unsigned short x, y;
+ PATH_NODE *next;
+};
+
+struct NODE {
+ unsigned int id;
+ short job;
+ char coordinates[3];
+ NODE *next;
+ unsigned char type;
+ unsigned char action;
+ unsigned char frame;
+ PATH_NODE *path;
+ char *speech;
+ unsigned char speech_time;
+ int speech_color;
+ short tick_time;
+ short speed;
+ unsigned char emotion;
+ unsigned char emotion_time;
+ int text_x, text_y; // temp solution to fix speech position
+};
+
+void empty();
+NODE *get_head();
+NODE *create_node();
+PATH_NODE *create_path_node(unsigned short x, unsigned short y);
+void add_node(NODE *node);
+NODE *find_node(unsigned int id);
+void remove_node(unsigned int id);
+unsigned int get_count();
+bool remove_being(char *data);
+void remove_being(unsigned int id);
+int get_beings_size();
+bool is_being(int id);
+void popup_being(unsigned char type, char *data);
+void move_being(char *data);
+PATH_NODE *calculate_path(unsigned short src_x, unsigned short src_y, unsigned short dest_x, unsigned short dest_y);
+unsigned int get_id(NODE *node);
+unsigned int find_npc(unsigned short x, unsigned short y);
+unsigned int find_monster(unsigned short x, unsigned short y);
+void sort();
+
+extern NODE *player_node;
+
+#endif
diff --git a/src/game.cpp b/src/game.cpp
new file mode 100644
index 00000000..ac90b56b
--- /dev/null
+++ b/src/game.cpp
@@ -0,0 +1,663 @@
+/**
+
+ 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
+
+*/
+
+#include "main.h"
+#include "map.h"
+#include "being.h"
+#include "log.h"
+#include "./Gui/chat.h"
+#include "./Gui/gui.h"
+#include "./Gui/inventory.h"
+#include "./Graphic/SuperEagle.h"
+#include "./Graphic/graphic.h"
+#include "./Sound/sound.h"
+
+char map_path[480];
+
+extern TmwSound sound;
+
+unsigned short dest_x, dest_y, src_x, src_y;
+unsigned int player_x, player_y;
+bool refresh_beings = false;
+unsigned char keyb_state;
+volatile int tick_time;
+volatile bool refresh = false, action_time = false;
+
+#define MAX_TIME 10000
+
+/** Finite states machine to keep track
+ of player walking status (2 steps linear
+ prediction)
+ 0 = Standing
+ 1 = Walking without confirm packet
+ 2 = Walking with confirm */
+char walk_status = 0;
+
+
+
+void refresh_time(void) {
+ tick_time++;
+ if(tick_time==MAX_TIME)tick_time = 0;
+}
+END_OF_FUNCTION(refresh_frame);
+
+void refresh_screen(void) {
+ refresh = true;
+}
+END_OF_FUNCTION(refresh_screen);
+
+int fps = 0, frame = 0;
+/** lets u only trigger an action every other second
+ tmp. counts fps*/
+void second(void) {
+ action_time = true;
+ fps = (fps + frame)/2;
+ frame = 0;
+}
+END_OF_FUNCTION(second);
+
+/** Return elapsed time (Warning: very unsafe
+ function. It supposes the delay is always < 10s) */
+short get_elapsed_time(short start_time) {
+ if(start_time<=tick_time)
+ return tick_time-start_time;
+ else
+ return tick_time+(MAX_TIME-start_time);
+}
+
+/** Main game loop */
+void game() {
+ status("INIT");
+ do_init();
+ init_graphic();
+ while(state!=EXIT) {
+ status("INPUT");
+ do_input();
+ status("LOGIC");
+ do_logic();
+ if(refresh) {
+ status("GRAPHIC");
+ do_graphic();
+ refresh = false;
+ }
+ status("PARSE");
+ do_parse();
+ status("FLUSH");
+ flush();
+ }
+
+ exit_graphic();
+ close_session();
+}
+
+/** Initialize game engine */
+void do_init() {
+
+ if(!load_map(map_path))error("Could not find map file");
+
+ sound.StartMOD("Sound/Mods/somemp.xm",-1);
+
+ // Initialize timers
+ tick_time = 0;
+ refresh = false;
+ LOCK_VARIABLE(tick_time);
+ LOCK_VARIABLE(refresh);
+ install_int_ex(refresh_time, MSEC_TO_TIMER(1));
+ install_int_ex(refresh_screen, /*MSEC_TO_TIMER(2000)*/BPS_TO_TIMER(75)); // Set max refresh rate to 75 fps
+ install_int_ex(second, BPS_TO_TIMER(1));
+
+ // Interrupt drawing while in background
+ #ifdef WIN32
+ set_display_switch_mode(SWITCH_AMNESIA);
+ #else
+ set_display_switch_mode(SWITCH_PAUSE);
+ #endif
+
+ // Initialize beings
+ empty();
+ player_node = create_node();
+ player_node->id = account_ID;
+ player_node->type = ACTION_NODE;
+ set_coordinates(player_node->coordinates, x, y, 0);
+ player_node->speed = 150;
+ add_node(player_node);
+ keyb_state = IDLE;
+
+ remove("packet.list");
+}
+
+/** Clean the engine */
+void do_exit() {
+}
+
+/** Check user input */
+void do_input() {
+
+ if(walk_status==0) {
+ int x = get_x(player_node->coordinates);
+ int y = get_y(player_node->coordinates);
+
+ if(key[KEY_UP]) {
+ if(get_walk(x, y-1)!=0) {
+ walk(x, y-1, NORTH);
+ walk_status = 1;
+ src_x = x;
+ src_y = y;
+ player_node->action = WALK;
+ player_node->tick_time = tick_time;
+ set_coordinates(player_node->coordinates, x, y-1, NORTH);
+ } else set_coordinates(player_node->coordinates, x, y, NORTH);
+ } else if(key[KEY_DOWN]) {
+ if(get_walk(x, y+1)!=0) {
+ walk(x, y+1, SOUTH);
+ walk_status = 1;
+ src_x = x;
+ src_y = y;
+ player_node->action = WALK;
+ player_node->tick_time = tick_time;
+ set_coordinates(player_node->coordinates, x, y+1, SOUTH);
+ } else set_coordinates(player_node->coordinates, x, y, SOUTH);
+ } else if(key[KEY_LEFT]) {
+ if(get_walk(x-1, y)!=0) {
+ walk(x-1, y, WEST);
+ walk_status = 1;
+ src_x = x;
+ src_y = y;
+ player_node->action = WALK;
+ player_node->tick_time = tick_time;
+ set_coordinates(player_node->coordinates, x-1, y, WEST);
+ } else set_coordinates(player_node->coordinates, x, y, WEST);
+ } else if(key[KEY_RIGHT]) {
+ if(get_walk(x+1, y)!=0) {
+ walk(x+1, y, EAST);
+ walk_status = 1;
+ src_x = x;
+ src_y = y;
+ player_node->action = WALK;
+ player_node->tick_time = tick_time;
+ set_coordinates(player_node->coordinates, x+1, y, EAST);
+ } else set_coordinates(player_node->coordinates, x, y, EAST);
+ }
+ }
+
+ if(player_node->action==STAND)
+ if(key[KEY_LCONTROL]) {
+ player_node->action = ATTACK;
+ attack(x, y, get_direction(player_node->coordinates));
+ player_node->tick_time = tick_time;
+ }
+
+ if(key[KEY_F1]) {
+ save_bitmap("./Graphic/screenshot.bmp",double_buffer,NULL);
+ } else if(key[KEY_F12]){
+ sound.SetAdjVol( 1, 1, 1);
+ } else if(key[KEY_F11]){
+ sound.SetAdjVol(-1,-1,-1);
+ }
+ if(key[KEY_F5] && action_time==true) {
+ if(player_node->action==STAND)
+ action(2, 0);
+ else if(player_node->action==SIT)
+ action(3, 0);
+ action_time = false;
+ }
+ if(key[KEY_F6] && action_time==true) {
+ inventory.toggle();
+ action_time = false;
+ }
+
+ if(key[KEY_ENTER]) {
+ if(strcmp(speech, "")!=0) {
+ chatlog.chat_send(char_info[0].name, speech);
+ strcpy(speech,"");
+ }
+ }
+
+ if(mouse_b&2) {
+ if(!show_npc_dialog) {
+ int npc_x = mouse_x/32+map_x/32;
+ int npc_y = mouse_y/32+map_y/32;
+ int id = find_npc(npc_x+1, npc_y+1);
+ if(id!=0) {
+ WFIFOW(0) = net_w_value(0x0090);
+ WFIFOL(2) = net_l_value(id);
+ WFIFOB(6) = 0;
+ WFIFOSET(7);
+ }
+ }
+ }
+
+ // Emotions, Skill dialog
+ if(key_shifts & KB_ALT_FLAG && action_time == true) {
+ if(player_node->emotion==0) {
+ unsigned char emotion = 0;
+ if(key[KEY_1])
+ emotion = 1;
+ else if(key[KEY_2])
+ emotion = 2;
+ else if(key[KEY_3])
+ emotion = 3;
+ else if(key[KEY_4])
+ emotion = 4;
+ else if(key[KEY_5])
+ emotion = 5;
+ else if(key[KEY_6])
+ emotion = 6;
+ else if(key[KEY_7])
+ emotion = 7;
+ else if(key[KEY_8])
+ emotion = 8;
+ else if(key[KEY_9])
+ emotion = 9;
+ else if(key[KEY_0])
+ emotion = 10;
+ if(emotion!=0) {
+ WFIFOW(0) = net_w_value(0x00bf);
+ WFIFOB(2) = emotion;
+ WFIFOSET(3);
+ action_time = false;
+ }
+ }
+
+ if(key[KEY_S]) {
+ show_skill_dialog = !show_skill_dialog;
+ action_time = false;
+ }
+ }
+
+ if(key[KEY_ESC])state = EXIT;
+
+}
+
+
+
+/** Update game logic */
+void do_logic() {
+}
+
+/** Calculate packet length */
+int get_packet_length(short id) {
+ int len = get_length(id);
+ if(len==-1)len = RFIFOW(2);
+ return len;
+}
+
+/** Parse data received from map server into input buffer */
+void do_parse() {
+ unsigned short id;
+ char *temp;
+ char direction;
+ NODE *node = NULL;
+ int len;
+
+
+ // We need at least 2 bytes to identify a packet
+ if(in_size>=2) {
+ // Check if the received packet is complete
+ while(in_size>=(len = get_packet_length(id = RFIFOW(0)))) {
+ // Add infos to log file and dump the latest received packet
+ char pkt_nfo[60];
+ sprintf(pkt_nfo,"In-buffer size: %i Packet id: %x Packet length: %i",in_size,RFIFOW(0),len);
+ /*log_hex("Packet", "Packet_ID", RFIFOW(0));
+ log_int("Packet", "Packet_length", get_length(RFIFOW(0)));
+ log_int("Packet", "Packet_in_size", RFIFOW(2));
+ log_int("Packet", "In_size", in_size);
+ FILE *file = fopen("packet.dump", "wb");
+ for(int i=0;i<len;i++) {
+ fprintf(file, "%x|%i|%c ", RFIFOB(i), RFIFOB(i), RFIFOB(i));
+ if((i+1)%10==0)fprintf(file, "\n");
+ }
+ fclose(file);
+ file = fopen("packet.list", "ab");
+ fprintf(file, "%x\n", RFIFOW(0));
+ fclose(file);*/
+
+ // Parse packet based on their id
+ switch(id) {
+ // Received speech
+ case 0x008d:
+ temp = (char *)malloc(RFIFOW(2)-8);
+ memset(temp, '\0', RFIFOW(2)-8);
+ memcpy(temp, RFIFOP(8), RFIFOW(2)-8);
+ node = find_node(RFIFOL(4));
+ if(node!=NULL) {
+ if(node->speech!=NULL) {
+ free(node->speech);
+ node->speech = NULL;
+ node->speech_time = 0;
+ }
+ node->speech = temp;
+ node->speech_time = SPEECH_TIME;
+ node->speech_color = makecol(255, 255, 255);
+ chatlog.chat_log(node->speech, BY_OTHER, gui_font);
+ }
+ break;
+ case 0x008e:
+ case 0x009a:
+ temp = (char *)malloc(RFIFOW(2)-4);
+ memset(temp, '\0', RFIFOW(2)-4);
+ memcpy(temp, RFIFOP(4), RFIFOW(2)-4);
+ if(player_node->speech!=NULL) {
+ free(player_node->speech);
+ player_node->speech = NULL;
+ node->speech_time = 0;
+ }
+ player_node->speech = temp;
+ player_node->speech_time = SPEECH_TIME;
+ player_node->speech_color = makecol(255, 255, 255);
+ if(id==0x008e)
+ chatlog.chat_log(player_node->speech, BY_PLAYER, gui_font);
+ else
+ chatlog.chat_log(player_node->speech, BY_GM, gui_font);
+ break;
+ // Success to walk request
+ case 0x0087:
+ /*if(walk_status==1) {
+ if(get_dest_x(RFIFOP(6))==get_x(player_node->coordinates) && get_dest_y(RFIFOP(6))==get_y(player_node->coordinates))*/
+ if(walk_status==1)
+ walk_status = 2;
+ /*else {
+ walk_status = 0;
+ set_coordinates(player_node->coordinates, src_x, src_y, get_direction(player_node->coordinates));
+ player_node->action = STAND;
+ }
+ }*/
+ break;
+ // Add new being
+ case 0x0078:
+ if(find_node(RFIFOL(2))==NULL) {
+ node = create_node();
+ node->id = RFIFOL(2);
+ node->speed = RFIFOW(6);
+ if(node->speed==0)node->speed = 150; // Else division by 0 when calculating frame
+ node->job = RFIFOW(14);
+ memcpy(node->coordinates, RFIFOP(46), 3);
+ add_node(node);
+ }
+ break;
+ // Remove a being
+ case 0x0080:
+ node = find_node(RFIFOL(2));
+ if(node!=NULL) {
+ if(RFIFOB(6)==1) { // Death
+ if(node->job>110) {
+ node->action = MONSTER_DEAD;
+ node->frame = 0;
+ node->tick_time = tick_time;
+ } else remove_node(RFIFOL(2));
+ } else remove_node(RFIFOL(2));
+ }
+ break;
+ // Player moving
+ case 0x01d8:
+ case 0x01d9:
+ node = find_node(RFIFOL(2));
+ if(node==NULL) {
+ node = create_node();
+ node->id = RFIFOL(2);
+ node->job = RFIFOW(16);
+ memcpy(node->coordinates, RFIFOP(46), 3);
+ add_node(node);
+ node->tick_time = tick_time;
+ node->speed = RFIFOW(6);
+ }
+ break;
+ // Monster moving
+ case 0x007b:
+ node = find_node(RFIFOL(2));
+ if(node==NULL) {
+ node = create_node();
+ node->action = STAND;
+ set_coordinates(node->coordinates, get_src_x(RFIFOP(50)), get_src_y(RFIFOP(50)), 0);
+ node->id = RFIFOL(2);
+ node->speed = RFIFOW(6);
+ node->job = RFIFOW(14);
+ add_node(node);
+ }
+ node->path = calculate_path(get_src_x(RFIFOP(50)),get_src_y(RFIFOP(50)),get_dest_x(RFIFOP(50)),get_dest_y(RFIFOP(50)));
+ if(node->path!=NULL) {
+ set_coordinates(node->coordinates, node->path->x, node->path->y, 0);
+ node->action = WALK;
+ node->tick_time = tick_time;
+ }
+ break;
+ // Being moving
+ case 0x01da:
+ node = find_node(RFIFOL(2));
+ if(node==NULL) {
+ node = create_node();
+ node->id = RFIFOL(2);
+ node->job = RFIFOW(14);
+ set_coordinates(node->coordinates, get_src_x(RFIFOP(50)), get_src_y(RFIFOP(50)), 0);
+ add_node(node);
+ }
+ if(node->action!=WALK) {
+ direction = get_direction(node->coordinates);
+ node->action = WALK;
+ if(get_dest_x(RFIFOP(50))>get_x(node->coordinates))direction = EAST;
+ else if(get_dest_x(RFIFOP(50))<get_x(node->coordinates))direction = WEST;
+ else if(get_dest_y(RFIFOP(50))>get_y(node->coordinates))direction = SOUTH;
+ else if(get_dest_y(RFIFOP(50))<get_y(node->coordinates))direction = NORTH;
+ else node->action = STAND;
+ if(node->action==WALK)node->tick_time = tick_time;
+ set_coordinates(node->coordinates, get_dest_x(RFIFOP(50)), get_dest_y(RFIFOP(50)), direction);
+ }
+ break;
+ // NPC dialog
+ case 0x00b4:
+ if(!strstr(npc_text, RFIFOP(8))) {
+ strcat(npc_text, RFIFOP(8));
+ strcat(npc_text, "\n");
+ show_npc_dialog = 1;
+ }
+ break;
+ // Warp
+ case 0x0091:
+ memset(map_path, '\0', 480);
+ append_filename(map_path, "./data/map/", RFIFOP(2), 480);
+ if(load_map(map_path)) {
+ empty();
+ player_node = create_node();
+ player_node->job = 0;
+ player_node->action = STAND;
+ player_node->frame = 0;
+ player_node->type = ACTION_NODE;
+ player_node->speed = 150;
+ player_node->id = account_ID;
+ x = RFIFOW(18);
+ y = RFIFOW(20);
+ set_coordinates(player_node->coordinates, x, y, 0);
+ add_node(player_node);
+ walk_status = 0;
+ // Send "map loaded"
+ WFIFOW(0) = net_w_value(0x007d);
+ WFIFOSET(2);
+ while(out_size>0)flush();
+ } else error("Could not find map file");
+ break;
+ // Skill ...
+ case 0x011a:
+ break;
+ case 0x01a4:
+ break;
+ // Action failed (ex. sit because you have not reached the right level)
+ case 0x0110:
+ CHATSKILL action;
+
+ action.skill = RFIFOW(2);
+ action.bskill = RFIFOW(4);
+ action.unused = RFIFOW(6);
+ action.success = RFIFOB(8);
+ action.reason = RFIFOB(9);
+
+ if(action.success != SKILL_FAILED &&
+ action.bskill == BSKILL_EMOTE ) {
+ printf("Action: %d/%d", action.bskill, action.success);
+ }
+ chatlog.chat_log(action, gui_font);
+ break;
+ // Update stat values
+ case 0x00b0:
+ switch(RFIFOW(2)) {
+ case 5:
+ char_info->hp = RFIFOW(4);
+ break;
+ case 6:
+ char_info->max_hp = RFIFOW(4);
+ break;
+ case 7:
+ char_info->sp = RFIFOW(4);
+ break;
+ case 8:
+ char_info->max_sp = RFIFOW(4);
+ break;
+ case 11:
+ char_info->lv = RFIFOW(4);
+ break;
+ }
+ if(char_info->hp==0) {
+ ok("Message", "You're now dead, press ok to restart");
+ WFIFOW(0) = net_w_value(0x00b2);
+ WFIFOB(2) = 0;
+ WFIFOSET(3);
+ }
+ break;
+ // Stop walking
+ /*case 0x0088: // Disabled because giving some problems
+ if(node = find_node(RFIFOL(2))) {
+ if(node->id!=player_node->id) {
+ node->action = STAND;
+ node->frame = 0;
+ set_coordinates(node->coordinates, RFIFOW(6), RFIFOW(8), get_direction(node->coordinates));
+ }
+ }
+ break;*/
+ // Damage, sit, stand up
+ case 0x008a:
+ switch(RFIFOB(26)) {
+ case 0: // Damage
+ node = find_node(RFIFOL(6));
+ if(node!=NULL) {
+ if(node->speech!=NULL) {
+ free(node->speech);
+ node->speech = NULL;
+ node->speech_time = SPEECH_TIME;
+ }
+ node->speech = (char *)malloc(5);
+ memset(node->speech, '\0', 5);
+ if(RFIFOW(22)==0) {
+ sprintf(node->speech, "miss");
+ node->speech_color = makecol(255, 255, 0);
+ } else {
+ sprintf(node->speech, "%i", RFIFOW(22));
+ if(node->id!=player_node->id)node->speech_color = makecol(0, 0, 255);
+ else node->speech_color = makecol(255, 0, 0);
+ }
+ node->speech_time = SPEECH_TIME;
+ if(RFIFOL(2)!=player_node->id) {
+ node = find_node(RFIFOL(2));
+ if(node!=NULL) {
+ if(node->job<10)
+ node->action = ATTACK;
+ else node->action = MONSTER_ATTACK;
+ node->frame = 0;
+ }
+ }
+ }
+ break;
+ case 2: // Sit
+ case 3: // Stand up
+ node = find_node(RFIFOL(2));
+ if(node!=NULL) {
+ if(RFIFOB(26)==2)
+ node->action = SIT;
+ else if(RFIFOB(26)==3)
+ node->action = STAND;
+ }
+ break;
+ }
+ break;
+ // Status change
+ case 0x00b1:
+ switch(RFIFOW(2)) {
+ case 1:
+ char_info->xp = RFIFOL(4);
+ break;
+ case 2:
+ char_info->job_xp = RFIFOL(4);
+ break;
+ case 14:
+ char_info->zeny = RFIFOL(4);
+ break;
+ // case 16 and 17 missing
+ }
+ break;
+ // Level up
+ case 0x019b:
+ if(RFIFOW(2)==0) {
+ ok("Info", "Level up!");
+ } else if(RFIFOW(2)==1) {
+ ok("Info", "Job level up!");
+ }
+ break;
+ // Emotion
+ case 0x00c0:
+ node = find_node(RFIFOL(2));
+ if(node) {
+ node->emotion = RFIFOB(6);
+ node->emotion_time = EMOTION_TIME;
+ }
+ break;
+ // Update skill values
+ case 0x0141:
+ switch(RFIFOL(2)) {
+ case 0x000d:
+ char_info->STR = RFIFOL(6) + RFIFOL(10); // Base + Bonus
+ break;
+ case 0x000e:
+ char_info->AGI = RFIFOL(6) + RFIFOL(10);
+ break;
+ case 0x000f:
+ char_info->VIT = RFIFOL(6) + RFIFOL(10);
+ break;
+ case 0x0010:
+ char_info->INT = RFIFOL(6) + RFIFOL(10);
+ break;
+ case 0x0011:
+ char_info->DEX = RFIFOL(6) + RFIFOL(10);
+ break;
+ case 0x0012:
+ char_info->LUK = RFIFOL(6) + RFIFOL(10);
+ break;
+ }
+ break;
+ // Manage non implemented packets
+ default:
+ //alert(pkt_nfo,"","","","",0,0);
+ break;
+ }
+ //alert(pkt_nfo,"","","","",0,0);
+
+ RFIFOSKIP(len);
+ }
+ }
+}
diff --git a/src/game.h b/src/game.h
new file mode 100644
index 00000000..8a48d046
--- /dev/null
+++ b/src/game.h
@@ -0,0 +1,92 @@
+/**
+
+ 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
+
+*/
+
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#ifndef _GAME_H
+#define _GAME_H
+
+#include <allegro.h>
+#include <stdio.h>
+
+#include "main.h"
+#include "./Gui/gui.h"
+#include "./Gui/skill.h"
+#include "./Graphic/SuperEagle.h"
+
+#define SPEECH_TIME 40
+#define EMOTION_TIME 40
+#define SPEECH_MAX_TIME 100
+
+#define MAKECOL_WHITE makecol(255,255,255)
+#define MAKECOL_BLACK makecol(0,0,0)
+
+#define GET_WALKING_SPEECH_XCOORDS ((get_x(node->coordinates)-map_x+13)*16-25-(alfont_text_length(gui_font, node->speech)/2)-player_x-coeff_x*(16-4*node->frame))
+#define GET_WALKING_SPEECH_YCOORDS ((get_y(node->coordinates)-map_y+6)*16-55-player_y-coeff_y*(16-4*node->frame))
+
+#define GET_STANDING_SPEECH_XCOODRS ((get_x(node->coordinates)-map_x+13)*16-25-(alfont_text_length(gui_font, node->speech)/2)-player_x)
+#define GET_STANDING_SPEECH_YCOORDS ((get_y(node->coordinates)-map_y+6)*16-55-player_y)
+
+#define PLAYERSETS 4
+#define SIT 17
+#define STAND 0
+#define WALK 1
+#define MONSTER_ATTACK 5
+#define MONSTER_DEAD 9
+#define ATTACK 7
+#define LOCK 254
+#define IDLE 255
+
+#define SOUTH 0
+#define SW 1
+#define WEST 2
+#define NW 3
+#define NORTH 4
+#define NE 5
+#define EAST 6
+#define SE 7
+
+extern char map_path[480];
+extern DIALOG skill_dialog[];
+extern int fps, frame;
+extern char walk_status;
+extern unsigned short src_x, src_y, x, y;
+extern volatile int tick_time;
+
+void game();
+void do_init();
+void do_input();
+void do_parse();
+void do_graphic();
+void do_logic();
+void do_exit();
+int get_packet_length(short);
+
+char get_x_offset(char, char);
+char get_y_offset(char, char);
+
+short get_elapsed_time(short start_time);
+
+#endif
diff --git a/src/graphic/graphic.cpp b/src/graphic/graphic.cpp
new file mode 100644
index 00000000..3a6e71a3
--- /dev/null
+++ b/src/graphic/graphic.cpp
@@ -0,0 +1,256 @@
+/**
+
+ 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
+
+ By ElvenProgrammer aka Eugenio Favalli (umperio@users.sourceforge.net)
+
+*/
+
+#include "graphic.h"
+
+#define TILESET_W 480
+#define TILESET_H 320
+
+#ifdef WIN32
+#pragma warning (disable:4312)
+#endif
+
+#include <allegro.h>
+#include "../game.h"
+#include "../map.h"
+#include "../being.h"
+#include "../Gui/chat.h"
+#include "../Gui/inventory.h"
+#include "../data/graphic/gfx_data.h"
+
+BITMAP *buffer, *double_buffer, *chat_background;
+DATAFILE *tileset;
+char page_num;
+int map_x, map_y;
+DIALOG_PLAYER *chat_player, *npc_player, *skill_player;
+char speech[255] = "";
+char npc_text[1000] = "";
+TmwInventory inventory;
+Chat chatlog("chatlog.txt", 20);
+int show_npc_dialog = 0;
+bool show_skill_dialog = false;
+
+DIALOG npc_dialog[] = {
+ /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
+ { tmw_dialog_proc, 300, 200, 260, 150, 0, 0, 0, 0, 0, 0, (char *)"NPC", NULL, NULL },
+ { tmw_button_proc, 508, 326, 50, 20, 255, 0, 'c', D_EXIT, 0, 0, (char *)"&Close", NULL, NULL },
+ { tmw_textbox_proc, 304, 224, 252, 100, 0, 0, 0, 0, 0, 0, npc_text, NULL, NULL },
+ { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
+};
+
+DIALOG chat_dialog[] = {
+ /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
+ { tmw_edit_proc, 0, 574, 592, 25, 0, 0, 'c', 0, 90, 0, speech, NULL, NULL },
+ { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
+};
+
+int get_x_offset(NODE *node) {
+ int offset = 0;
+ char direction = get_direction(node->coordinates);
+ if(node->action==WALK) {
+ if(direction==WEST || direction==EAST) {
+ offset = node->frame + 1;
+ if(offset==5)offset = 0;
+ offset *= 4;
+ if(direction==WEST) {
+ offset = -offset;
+ offset += 16;
+ } else offset -= 16;
+ }
+ }
+ return offset;
+}
+
+int get_y_offset(NODE *node) {
+ int offset = 0;
+ char direction = get_direction(node->coordinates);
+ if(node->action==WALK) {
+ if(direction==SOUTH || direction==NORTH) {
+ offset = node->frame + 1;
+ if(offset==5)offset = 0;
+ offset *= 4;
+ if(direction==NORTH) {
+ offset = -offset;
+ offset += 16;
+ } else offset -= 16;
+ }
+ }
+ return offset;
+}
+
+void init_graphic() {
+ tileset = load_datafile("./data/graphic/village.dat");
+ //if(!(gfx_capabilities & GFX_HW_VRAM_BLIT))allegro_message("Not supporting HW accelerated blit");
+ buffer = create_bitmap(SCREEN_W/2, SCREEN_H/2);
+ double_buffer = create_bitmap(SCREEN_W, SCREEN_H);
+
+ alfont_set_font_size(gui_font, 16);
+ clear_bitmap(screen);
+ chat_background = create_bitmap(592, 100);
+ clear_to_color(chat_background, makecol(0,0,0));
+
+ // Initialize gui
+ chat_player = init_dialog(chat_dialog, -1);
+ npc_player = init_dialog(npc_dialog, -1);
+ position_dialog(npc_dialog, 300, 200);
+ skill_player = init_dialog(skill_dialog, -1);
+ gui_bitmap = double_buffer;
+ alfont_text_mode(-1);
+ inventory.create(0, 0);
+}
+
+void do_graphic(void) {
+
+ map_x = (get_x(player_node->coordinates)-13)*16+get_x_offset(player_node);
+ map_y = (get_y(player_node->coordinates)-9)*16+get_y_offset(player_node);
+
+ int camera_x = map_x >> 4;
+ int camera_y = map_y >> 4;
+
+ int offset_x = map_x & 15;
+ int offset_y = map_y & 15;
+
+ sort();
+
+ for(int j=0;j<20;j++)
+ for(int i=0;i<26;i++) {
+ draw_rle_sprite(buffer, (RLE_SPRITE *)tileset[get_tile(i+camera_x, j+camera_y, 0)].dat, i*16-offset_x, j*16-offset_y);
+ if(get_tile(i+camera_x, j+camera_y, 1)!=0)draw_rle_sprite(buffer, (RLE_SPRITE *)tileset[get_tile(i+camera_x, j+camera_y, 1)].dat, i*16-offset_x, j*16-offset_y);
+ }
+
+ NODE *node = get_head();
+ NODE *old_node = NULL;
+ while(node) {
+ if((node->job>=100)&&(node->job<=110)) { // Draw a NPC
+ masked_blit((BITMAP *)graphic[NPCSET_BMP].dat, buffer, (get_direction(node->coordinates)/2+4*(node->job-100))*25, 0, (get_x(node->coordinates)-camera_x)*16-4-offset_x, (get_y(node->coordinates)-camera_y)*16-24-offset_y, 25, 40);
+ } else if(node->job<10) { // Draw a player
+
+ node->text_x = (get_x(node->coordinates)-camera_x)*16-34+get_x_offset(node)-offset_x;
+ node->text_y = (get_y(node->coordinates)-camera_y)*16-36+get_y_offset(node)-offset_y;
+ masked_blit((BITMAP *)graphic[PLAYERSET_BMP].dat, buffer, 80*(get_direction(node->coordinates)/2), 60*(node->frame+node->action), node->text_x, node->text_y, 80, 60);
+
+ if(node->emotion!=0) {
+ draw_sprite(buffer, (BITMAP *)emotions[node->emotion-1].dat, (get_x(node->coordinates)-camera_x)*16-5+get_x_offset(node)-offset_x, (get_y(node->coordinates)-camera_y)*16-45+get_y_offset(node)-offset_y);
+ node->emotion_time--;
+ if(node->emotion_time==0)
+ node->emotion = 0;
+ }
+
+ if(node->action!=STAND && node->action!=SIT) {
+ node->frame = (get_elapsed_time(node->tick_time)*4)/(node->speed);
+ if(node->frame>=4) {
+ node->frame = 0;
+ node->action = STAND;
+ node->tick_time;
+ if(node->id==player_node->id)
+ walk_status = 0;
+ }
+ }
+
+ } else if(node->job==45) { // Draw a warp
+ //rectfill(buffer, (get_x(node->coordinates)-map_x)*16-player_x-get_x_offset(node->frame, get_direction(node->coordinates)), (get_y(node->coordinates)-map_y)*16-player_y-get_y_offset(node->frame, get_direction(node->coordinates)), (get_x(node->coordinates)-map_x)*16-player_x-get_x_offset(node->frame, get_direction(node->coordinates))+16, (get_y(node->coordinates)-map_y)*16-player_y-get_y_offset(node->frame, get_direction(node->coordinates))+16, makecol(0,0,255));
+ } else { // Draw a monster
+
+ node->text_x = (get_x(node->coordinates)-camera_x)*16-20+get_x_offset(node)-offset_x;
+ node->text_y = (get_y(node->coordinates)-camera_y)*16-25+get_y_offset(node)-offset_y;
+
+ if(node->action==MONSTER_DEAD)node->frame = 0;
+ masked_blit((BITMAP *)graphic[MOBSET_BMP].dat, buffer, (get_direction(node->coordinates)/2)*60, 60*(node->frame+node->action), node->text_x, node->text_y, 60, 60);
+ if(node->action!=STAND) {
+ node->frame = (get_elapsed_time(node->tick_time)*4)/(node->speed);
+ if(node->frame>=4) {
+ if(node->action!=MONSTER_DEAD) {
+ if(node->path && node->action!=MONSTER_DEAD) {
+ PATH_NODE *old = node->path;
+ set_coordinates(node->coordinates, node->path->x, node->path->y, 0);
+ node->path = node->path->next;
+ if(old!=NULL)
+ free(old);
+ } else node->action = STAND;
+ if(node->action!=MONSTER_DEAD)node->frame = 0;
+ node->tick_time = tick_time;
+ }
+ }
+ }
+ }
+ old_node = node;
+ node = node->next;
+ if(old_node->action==MONSTER_DEAD && old_node->frame>=4)
+ remove_node(old_node->id);
+ }
+
+ for(int j=0;j<20;j++)
+ for(int i=0;i<26;i++) {
+ if(get_tile(i+camera_x, j+camera_y, 2)!=0)draw_rle_sprite(buffer, (RLE_SPRITE *)tileset[get_tile(i+camera_x, j+camera_y, 2)].dat, i*16-offset_x, j*16-offset_y);
+ }
+
+ stretch_blit(buffer, double_buffer, 0, 0, 400, 300, 0, 0, 800, 600);
+
+ // Draw player speech
+ node = get_head();
+ while(node) {
+ if(node->speech!=NULL) {
+ alfont_textprintf_aa(double_buffer, gui_font, node->text_x+260-alfont_text_length(gui_font, node->speech)/2, node->text_y+100, node->speech_color, "%s", node->speech);
+
+ node->speech_time--;
+ if(node->speech_time==0) {
+ free(node->speech);
+ node->speech = NULL;
+ }
+ }
+ node = node->next;
+ }
+
+ inventory.draw(double_buffer);
+
+ set_trans_blender(0, 0, 0, 110);
+ draw_trans_sprite(double_buffer, chat_background, 0, SCREEN_H-125);
+
+ chatlog.chat_draw(double_buffer, 8, gui_font);
+ gui_update(chat_player);
+
+ if(show_npc_dialog) {
+ dialog_message(npc_dialog,MSG_DRAW,0,0);
+ if(!(show_npc_dialog = gui_update(npc_player)))strcpy(npc_text, "");
+ }
+
+ if(show_skill_dialog) {
+ update_skill_dialog();
+ if(gui_update(skill_player)==0)show_skill_dialog = false;
+ }
+
+
+ alfont_textprintf_aa(double_buffer, gui_font, 0, 0, MAKECOL_WHITE, "FPS:%i", fps);
+
+ blit(double_buffer, screen, 0, 0, 0, 0, 800, 600);
+
+ frame++;
+}
+
+void exit_graphic() {
+ shutdown_dialog(npc_player);
+ shutdown_dialog(chat_player);
+ shutdown_dialog(skill_player);
+}
diff --git a/src/graphic/graphic.h b/src/graphic/graphic.h
new file mode 100644
index 00000000..c50def22
--- /dev/null
+++ b/src/graphic/graphic.h
@@ -0,0 +1,50 @@
+/**
+
+ 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
+
+ By ElvenProgrammer aka Eugenio Favalli (umperio@users.sourceforge.net)
+
+*/
+
+#ifndef _GRAPHIC_H
+#define _GRAPHIC_H
+
+#ifdef WIN32
+#pragma warning (disable:4312)
+#endif
+
+#include <allegro.h>
+#include "../Gui/chat.h"
+#include "../Gui/inventory.h"
+
+extern BITMAP *buffer, *double_buffer;
+extern char speech[255];
+extern char npc_text[1000];
+extern Chat chatlog;
+extern bool show_skill_dialog;
+extern int show_npc_dialog;
+extern TmwInventory inventory;
+extern int map_x, map_y;
+
+void do_graphic(void);
+void init_graphic(void);
+void exit_graphic(void);
+
+#endif
diff --git a/src/graphic/super_eagle.cpp b/src/graphic/super_eagle.cpp
new file mode 100644
index 00000000..78bb6fea
--- /dev/null
+++ b/src/graphic/super_eagle.cpp
@@ -0,0 +1,450 @@
+/**
+
+ 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
+
+*/
+
+#include "SuperEagle.h"
+
+static uint32 colorMask = 0xF7DEF7DE;
+static uint32 lowPixelMask = 0x08210821;
+static uint32 qcolorMask = 0xE79CE79C;
+static uint32 qlowpixelMask = 0x18631863;
+static uint32 redblueMask = 0xF81F;
+static uint32 greenMask = 0x7E0;
+static int PixelsPerMask = 2;
+static int xsai_depth = 0;
+
+int Init_SuperEagle(int d) {
+ int minr = 0, ming = 0, minb = 0;
+ int i;
+
+ if (d != 15 && d != 16 && d != 24 && d != 32)
+ return -1;
+
+ /* Get lowest color bit */
+ for (i = 0; i < 255; i++) {
+ if (!minr)
+ minr = makecol(i, 0, 0);
+ if (!ming)
+ ming = makecol(0, i, 0);
+ if (!minb)
+ minb = makecol(0, 0, i);
+ }
+
+ colorMask = (makecol_depth(d, 255, 0, 0) - minr) | (makecol_depth(d, 0, 255, 0) - ming) | (makecol_depth(d, 0, 0, 255) - minb);
+ lowPixelMask = minr | ming | minb;
+ qcolorMask = (makecol_depth(d, 255, 0, 0) - 3 * minr) | (makecol_depth(d, 0, 255, 0) - 3 * ming) | (makecol_depth(d, 0, 0, 255) - 3 * minb);
+ qlowpixelMask = (minr * 3) | (ming * 3) | (minb * 3);
+ redblueMask = makecol_depth(d, 255, 0, 255);
+ greenMask = makecol_depth(d, 0, 255, 0);
+
+ PixelsPerMask = (d <= 16) ? 2 : 1;
+
+ if (PixelsPerMask == 2) {
+ colorMask |= (colorMask << 16);
+ qcolorMask |= (qcolorMask << 16);
+ lowPixelMask |= (lowPixelMask << 16);
+ qlowpixelMask |= (qlowpixelMask << 16);
+ }
+
+ TRACE("Color Mask: 0x%lX\n", colorMask);
+ TRACE("Low Pixel Mask: 0x%lX\n", lowPixelMask);
+ TRACE("QColor Mask: 0x%lX\n", qcolorMask);
+ TRACE("QLow Pixel Mask: 0x%lX\n", qlowpixelMask);
+
+ xsai_depth = d;
+
+ return 0;
+}
+
+/** unused /- kth5
+static int GetResult1(uint32 A, uint32 B, uint32 C, uint32 D) {
+ int x = 0;
+ int y = 0;
+ int r = 0;
+ if (A == C)
+ x += 1;
+ else if (B == C)
+ y += 1;
+ if (A == D)
+ x += 1;
+ else if (B == D)
+ y += 1;
+ if (x <= 1)
+ r += 1;
+ if (y <= 1)
+ r -= 1;
+ return r;
+}
+
+static int GetResult2(uint32 A, uint32 B, uint32 C, uint32 D, uint32 E) {
+ int x = 0;
+ int y = 0;
+ int r = 0;
+ if (A == C)
+ x += 1;
+ else if (B == C)
+ y += 1;
+ if (A == D)
+ x += 1;
+ else if (B == D)
+ y += 1;
+ if (x <= 1)
+ r -= 1;
+ if (y <= 1)
+ r += 1;
+ return r;
+}*/
+
+
+#define GET_RESULT(A, B, C, D) ((A != C || A != D) - (B != C || B != D))
+
+#define INTERPOLATE(A, B) (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask))
+
+#define Q_INTERPOLATE(A, B, C, D) ((A & qcolorMask) >> 2) + ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2) \
+ + ((((A & qlowpixelMask) + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask)) >> 2) & qlowpixelMask)
+
+
+/* Clipping Macro, stolen from Allegro, modified to work with 2xSaI */
+#define BLIT_CLIP2(src, dest, s_x, s_y, d_x, d_y, w, h, xscale, yscale) \
+ /* check for ridiculous cases */ \
+ if ((s_x >= src->cr) || (s_y >= src->cb) || \
+ (d_x >= dest->cr) || (d_y >= dest->cb)) \
+ return; \
+ \
+ if ((s_x + w < src->cl) || (s_y + h < src->ct) || \
+ (d_x + w * xscale < dest->cl) || (d_y + h * yscale < dest->ct)) \
+ return; \
+ \
+ if (xscale < 1 || yscale < 1) \
+ return; \
+ \
+ /* clip src left */ \
+ if (s_x < src->cl) { \
+ w += s_x; \
+ d_x -= s_x * xscale; \
+ s_x = src->cl; \
+ } \
+ \
+ /* clip src top */ \
+ if (s_y < src->ct) { \
+ h += s_y; \
+ d_y -= s_y * yscale; \
+ s_y = src->ct; \
+ } \
+ \
+ /* clip src right */ \
+ if (s_x + w > src->cr) \
+ w = src->cr - s_x; \
+ \
+ /* clip src bottom */ \
+ if (s_y + h > src->cb) \
+ h = src->cb - s_y; \
+ \
+ /* clip dest left */ \
+ if (d_x < dest->cl) { \
+ d_x -= dest->cl; \
+ w += d_x / xscale; \
+ s_x -= d_x / xscale; \
+ d_x = dest->cl; \
+ } \
+ \
+ /* clip dest top */ \
+ if (d_y < dest->ct) { \
+ d_y -= dest->ct; \
+ h += d_y / yscale; \
+ s_y -= d_y / yscale; \
+ d_y = dest->ct; \
+ } \
+ \
+ /* clip dest right */ \
+ if (d_x + w * xscale > dest->cr) \
+ w = (dest->cr - d_x) / xscale; \
+ \
+ /* clip dest bottom */ \
+ if (d_y + h * yscale > dest->cb) \
+ h = (dest->cb - d_y) / yscale; \
+ \
+ /* bottle out if zero size */ \
+ if ((w <= 0) || (h <= 0)) \
+ return;
+
+
+static unsigned char *src_line[4];
+static unsigned char *dst_line[2];
+
+
+
+void SuperEagle(BITMAP * src, BITMAP * dest, int s_x, int s_y, int d_x, int d_y, int w, int h) {
+ int sbpp, dbpp;
+
+ BITMAP *dst2 = NULL;
+
+ if (!src || !dest)
+ return;
+
+ sbpp = bitmap_color_depth(src);
+ dbpp = bitmap_color_depth(dest);
+
+ if ((sbpp != xsai_depth) || (sbpp != dbpp)) /* Must be same color depth */
+ return;
+
+ BLIT_CLIP2(src, dest, s_x, s_y, d_x, d_y, w, h, 2, 2);
+
+ if (w < 4 || h < 4) { /* Image is too small to be 2xSaI'ed. */
+ stretch_blit(src, dest, s_x, s_y, w, h, d_x, d_y, w * 2, h * 2);
+ return;
+ }
+
+ sbpp = BYTES_PER_PIXEL(sbpp);
+ if (d_x || d_y)
+ dst2 = create_sub_bitmap(dest, d_x, d_y, w * 2, h * 2);
+
+ SuperEagle_ex(src->line[s_y] + s_x * sbpp, (unsigned int)(src->line[1] - src->line[0]), NULL, dst2 ? dst2 : dest, w, h);
+
+ if (dst2)
+ destroy_bitmap(dst2);
+
+ return;
+}
+
+void SuperEagle_ex(uint8 *src, uint32 src_pitch, uint8 *unused, BITMAP *dest, uint32 width, uint32 height) {
+
+ int j, v;
+ unsigned int x, y;
+ int sbpp = BYTES_PER_PIXEL(bitmap_color_depth(dest));
+ unsigned long color[12];
+
+ /* Point to the first 3 lines. */
+ src_line[0] = src;
+ src_line[1] = src;
+ src_line[2] = src + src_pitch;
+ src_line[3] = src + src_pitch * 2;
+
+ /* Can we write the results directly? */
+ if (is_video_bitmap(dest) || is_planar_bitmap(dest)) {
+ dst_line[0] = (unsigned char *)malloc(sizeof(char) * sbpp * width);
+ dst_line[1] = (unsigned char *)malloc(sizeof(char) * sbpp * width);
+ v = 1;
+ }
+ else {
+ dst_line[0] = dest->line[0];
+ dst_line[1] = dest->line[1];
+ v = 0;
+ }
+
+ /* Set destination */
+ bmp_select(dest);
+
+ x = 0, y = 0;
+
+ if (PixelsPerMask == 2) {
+ unsigned short *sbp;
+ sbp = (unsigned short*)src_line[0];
+ color[0] = *sbp; color[1] = color[0]; color[2] = color[0]; color[3] = color[0];
+ color[4] = *(sbp + 1); color[5] = *(sbp + 2);
+ sbp = (unsigned short*)src_line[2];
+ color[6] = *sbp; color[7] = color[6]; color[8] = *(sbp + 1); color[9] = *(sbp + 2);
+ sbp = (unsigned short*)src_line[3];
+ color[10] = *sbp; color[11] = *(sbp + 1);
+ }
+ else {
+ unsigned long *lbp;
+ lbp = (unsigned long*)src_line[0];
+ color[0] = *lbp; color[1] = color[0]; color[2] = color[0]; color[3] = color[0];
+ color[4] = *(lbp + 1); color[5] = *(lbp + 2);
+ lbp = (unsigned long*)src_line[2];
+ color[6] = *lbp; color[7] = color[6]; color[8] = *(lbp + 1); color[9] = *(lbp + 2);
+ lbp = (unsigned long*)src_line[3];
+ color[10] = *lbp; color[11] = *(lbp + 1);
+ }
+
+ for (y = 0; y < height; y++) {
+
+ /* Todo: x = width - 2, x = width - 1 */
+
+ for (x = 0; x < width; x++) {
+ unsigned long product1a, product1b, product2a, product2b;
+
+//--------------------------------------- B1 B2 0 1
+// 4 5 6 S2 -> 2 3 4 5
+// 1 2 3 S1 6 7 8 9
+// A1 A2 10 11
+
+ if (color[7] == color[4] && color[3] != color[8]) {
+ product1b = product2a = color[7];
+
+ if ((color[6] == color[7]) || (color[4] == color[1]))
+ product1a = INTERPOLATE(color[7], INTERPOLATE(color[7], color[3]));
+ else
+ product1a = INTERPOLATE(color[3], color[4]);
+
+ if ((color[4] == color[5]) || (color[7] == color[10]))
+ product2b = INTERPOLATE(color[7], INTERPOLATE(color[7], color[8]));
+ else
+ product2b = INTERPOLATE(color[7], color[8]);
+ }
+ else if (color[3] == color[8] && color[7] != color[4]) {
+ product2b = product1a = color[3];
+
+ if ((color[0] == color[3]) || (color[5] == color[9]))
+ product1b = INTERPOLATE(color[3], INTERPOLATE(color[3], color[4]));
+ else
+ product1b = INTERPOLATE(color[3], color[1]);
+
+ if ((color[8] == color[11]) || (color[2] == color[3]))
+ product2a = INTERPOLATE(color[3], INTERPOLATE(color[3], color[2]));
+ else
+ product2a = INTERPOLATE(color[7], color[8]);
+
+ }
+ else if (color[3] == color[8] && color[7] == color[4]) {
+ register int r = 0;
+
+ r += GET_RESULT(color[4], color[3], color[6], color[10]);
+ r += GET_RESULT(color[4], color[3], color[2], color[0]);
+ r += GET_RESULT(color[4], color[3], color[11], color[9]);
+ r += GET_RESULT(color[4], color[3], color[1], color[5]);
+
+ if (r > 0) {
+ product1b = product2a = color[7];
+ product1a = product2b = INTERPOLATE(color[3], color[4]);
+ }
+ else if (r < 0) {
+ product2b = product1a = color[3];
+ product1b = product2a = INTERPOLATE(color[3], color[4]);
+ }
+ else {
+ product2b = product1a = color[3];
+ product1b = product2a = color[7];
+ }
+ }
+ else {
+ product2b = product1a = INTERPOLATE(color[7], color[4]);
+ product2b = Q_INTERPOLATE(color[8], color[8], color[8], product2b);
+ product1a = Q_INTERPOLATE(color[3], color[3], color[3], product1a);
+
+ product2a = product1b = INTERPOLATE(color[3], color[8]);
+ product2a = Q_INTERPOLATE(color[7], color[7], color[7], product2a);
+ product1b = Q_INTERPOLATE(color[4], color[4], color[4], product1b);
+ }
+
+ if (PixelsPerMask == 2) {
+ *((unsigned long *) (&dst_line[0][x * 4])) = product1a | (product1b << 16);
+ *((unsigned long *) (&dst_line[1][x * 4])) = product2a | (product2b << 16);
+ }
+ else {
+ *((unsigned long *) (&dst_line[0][x * 8])) = product1a;
+ *((unsigned long *) (&dst_line[0][x * 8 + 4])) = product1b;
+ *((unsigned long *) (&dst_line[1][x * 8])) = product2a;
+ *((unsigned long *) (&dst_line[1][x * 8 + 4])) = product2b;
+ }
+
+ /* Move color matrix forward */
+ color[0] = color[1];
+ color[2] = color[3]; color[3] = color[4]; color[4] = color[5];
+ color[6] = color[7]; color[7] = color[8]; color[8] = color[9];
+ color[10] = color[11];
+
+ if (x < width - 2) {
+ x += 2;
+ if (PixelsPerMask == 2) {
+ color[1] = *(((unsigned short*)src_line[0]) + x);
+ if (x < width) {
+ color[5] = *(((unsigned short*)src_line[1]) + x + 1);
+ color[9] = *(((unsigned short*)src_line[2]) + x + 1);
+ }
+ color[11] = *(((unsigned short*)src_line[3]) + x);
+ }
+ else {
+ color[1] = *(((unsigned long*)src_line[0]) + x);
+ if (x < width) {
+ color[5] = *(((unsigned long*)src_line[1]) + x + 1);
+ color[9] = *(((unsigned long*)src_line[2]) + x + 1);
+ }
+ color[11] = *(((unsigned long*)src_line[3]) + x);
+ }
+ x -= 2;
+ }
+ }
+
+ /* We're done with one line, so we shift the source lines up */
+ src_line[0] = src_line[1];
+ src_line[1] = src_line[2];
+ src_line[2] = src_line[3];
+
+ /* Read next line */
+ if (y + 3 >= height)
+ src_line[3] = src_line[2];
+ else
+ src_line[3] = src_line[2] + src_pitch;
+
+ /* Then shift the color matrix up */
+ if (PixelsPerMask == 2) {
+ unsigned short *sbp;
+ sbp = (unsigned short*)src_line[0];
+ color[0] = *sbp; color[1] = *(sbp + 1);
+ sbp = (unsigned short*)src_line[1];
+ color[2] = *sbp; color[3] = color[2]; color[4] = *(sbp + 1); color[5] = *(sbp + 2);
+ sbp = (unsigned short*)src_line[2];
+ color[6] = *sbp; color[7] = color[6]; color[8] = *(sbp + 1); color[9] = *(sbp + 2);
+ sbp = (unsigned short*)src_line[3];
+ color[10] = *sbp; color[11] = *(sbp + 1);
+ }
+ else {
+ unsigned long *lbp;
+ lbp = (unsigned long*)src_line[0];
+ color[0] = *lbp; color[1] = *(lbp + 1);
+ lbp = (unsigned long*)src_line[1];
+ color[2] = *lbp; color[3] = color[2]; color[4] = *(lbp + 1); color[5] = *(lbp + 2);
+ lbp = (unsigned long*)src_line[2];
+ color[6] = *lbp; color[7] = color[6]; color[8] = *(lbp + 1); color[9] = *(lbp + 2);
+ lbp = (unsigned long*)src_line[3];
+ color[10] = *lbp; color[11] = *(lbp + 1);
+ }
+
+
+ /* Write the 2 lines, if not already done so */
+ if (v) {
+ unsigned long dst_addr;
+
+ dst_addr = bmp_write_line(dest, y * 2);
+ for (j = 0; j < dest->w * sbpp; j += sizeof(long))
+ bmp_write32(dst_addr + j, *((unsigned long *) (dst_line[0] + j)));
+
+ dst_addr = bmp_write_line(dest, y * 2 + 1);
+ for (j = 0; j < dest->w * sbpp; j += sizeof(long))
+ bmp_write32(dst_addr + j, *((unsigned long *) (dst_line[1] + j)));
+ }
+ else {
+ if (y < height - 1) {
+ dst_line[0] = dest->line[y * 2 + 2];
+ dst_line[1] = dest->line[y * 2 + 3];
+ }
+ }
+ }
+ bmp_unwrite_line(dest);
+
+ if (v) {
+ free(dst_line[0]);
+ free(dst_line[1]);
+ }
+}
diff --git a/src/graphic/super_eagle.h b/src/graphic/super_eagle.h
new file mode 100644
index 00000000..64c763db
--- /dev/null
+++ b/src/graphic/super_eagle.h
@@ -0,0 +1,44 @@
+/**
+
+ 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
+
+*/
+
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#ifndef _SUPER_EAGLE_H
+#define _SUPER_EAGLE_H
+
+#include <string.h>
+#include <allegro.h>
+#include <allegro/internal/aintern.h>
+
+#define uint32 unsigned long
+#define uint16 unsigned short
+#define uint8 unsigned char
+
+void SuperEagle(BITMAP * src, BITMAP * dest, int s_x, int s_y, int d_x, int d_y, int w, int h);
+void SuperEagle_ex(uint8 *src, uint32 src_pitch, uint8 *unused, BITMAP *dest, uint32 width, uint32 height);
+
+int Init_SuperEagle(int d);
+
+#endif
diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp
new file mode 100644
index 00000000..e58a8d73
--- /dev/null
+++ b/src/gui/char_select.cpp
@@ -0,0 +1,221 @@
+/**
+
+ 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
+
+*/
+
+#include "char_select.h"
+#include "../Graphic/graphic.h"
+
+char button_state[3];
+char address[41];
+char name[25];
+
+DIALOG char_select_dialog[] = {
+ /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
+ { tmw_dialog_proc, 300, 240, 200, 208, 0, -1, 0, 0, 0, 0, (char*)"Char select", NULL, NULL },
+ { tmw_text_proc, 308, 268, 192, 10, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
+ { tmw_bitmap_proc, 304, 282, 192, 70, 0, 0, 0, 0, 80, 60, playerset, NULL, NULL },
+ { tmw_button_proc, 398, 426, 44, 18, 0, -1, 'o', D_EXIT, -1, 0, (char*)"&Ok", NULL, NULL },
+ { tmw_button_proc, 446, 426, 44, 18, 0, -1, 'c', D_EXIT, -1, 0, (char*)"&Cancel", NULL, NULL },
+ { tmw_button_proc, 304, 426, 44, 18, 0, 0, 0, D_EXIT, 0, 0, button_state, NULL, NULL },
+/* { gui_button_proc, 304, 356, 20, 20, 0, 0, 0, 0, 0, 0, "<", NULL, NULL },
+ { gui_button_proc, 328, 356, 20, 20, 0, 0, 0, 0, 0, 0, ">", NULL, NULL }, */
+ { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
+};
+
+DIALOG char_create_dialog[] = {
+ /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
+ { tmw_dialog_proc, 276, 240, 248, 116, 0, -1, 0, 0, 0, 0, (char*)"Char create", NULL, NULL },
+ { tmw_text_proc, 280, 268, 192, 20, 0, 0, 0, 0, 0, 0, (char *)"Name: ", NULL, NULL },
+ { tmw_edit_proc, 336, 268, 162, 20, 0, 0, 0, 0, 24, 0, name, NULL, NULL },
+ { tmw_button_proc, 398, 334, 44, 18, 0, -1, 'o', D_EXIT, -1, 0, (char*)"&Ok", NULL, NULL },
+ { tmw_button_proc, 446, 334, 44, 18, 0, -1, 'c', D_EXIT, -1, 0, (char*)"&Cancel", NULL, NULL },
+ { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
+};
+
+void char_select() {
+ state = LOGIN;
+ if(n_character>0) {
+ char_select_dialog[1].dp = char_info->name;
+ char_select_dialog[1].x = 400-alfont_text_length(gui_font, char_info->name)/2;
+ char_select_dialog[2].dp = playerset;
+ if(playerset==NULL)ok("Error", "Playerset not loaded");
+ strcpy(button_state, "Del");
+ char_select_dialog[3].flags &= D_CLOSE;
+ } else {
+ char *temp = (char *)malloc(3);
+ strcpy(temp, "");
+ char_select_dialog[1].dp = temp;
+ char_select_dialog[3].flags |= D_DISABLED;
+ char_select_dialog[2].dp = NULL;
+ strcpy(button_state, "New");
+ }
+ //centre_dialog(char_select_dialog);
+ DIALOG_PLAYER *player = init_dialog(char_select_dialog, -1);
+ int gui_exit = 1;
+ while ((!key[KEY_ESC])&&(gui_exit)&&(!key[KEY_ENTER])) {
+ clear_bitmap(buffer);
+ if(stretch_mode!=0)blit((BITMAP *)graphic[LOGIN_BMP].dat, buffer, 0, 0, 80, 60, 640, 480);
+ else blit((BITMAP *)graphic[LOGIN_BMP].dat, buffer, 0, 0, -120, -90, 640, 480);
+ gui_exit = gui_update(player);
+ blit(buffer, screen, 0, 0, 0, 0, 800, 600);
+ }
+ gui_exit = shutdown_dialog(player);
+ if((gui_exit==3)||(key[KEY_ENTER]))server_char_select();
+ else if(gui_exit==4)close_session();
+ else if(gui_exit==5)server_char_delete();
+ if(state==LOGIN)close_session();
+}
+
+void server_char_select() {
+ // Request character selection
+ WFIFOW(0) = net_w_value(0x0066);
+ WFIFOB(2) = net_b_value(0);
+ WFIFOSET(3);
+
+ while((in_size<3)||(out_size>0))flush();
+ log_hex("Char_Select_Packet", "Packet_ID", RFIFOW(0));
+ log_int("Char_Select_Packet", "Packet_length", get_length(RFIFOW(0)));
+ log_int("Char_Select_Packet", "Packet_in_size", RFIFOW(2));
+ log_int("Char_Select_Packet", "In_size", in_size);
+
+ if(RFIFOW(0)==0x0071) {
+ while(in_size<28)flush();
+ char_ID = RFIFOL(2);
+ memset(map_path, '\0', 480);
+ append_filename(map_path, "./data/map/", RFIFOP(6), 480);
+ map_address = RFIFOL(22);
+ map_port = RFIFOW(26);
+ state = GAME;
+
+ log("Player", "map", map_name);
+ log("Char_Select_packet", "server_address", iptostring(map_address));
+ log_int("Char_Select_packet", "server_port", map_port);
+ RFIFOSKIP(28);
+ close_session();
+ } else if(RFIFOW(0)==0x006c) {
+ switch(RFIFOB(2)) {
+ case 0:
+ ok("Error", "Access denied");
+ break;
+ case 1:
+ ok("Error", "Cannot use this ID");
+ break;
+ }
+ state = CHAR_SELECT;
+ RFIFOSKIP(3);
+ }
+ // Todo: add other packets
+}
+
+void server_char_delete() {
+ state = CHAR_SELECT;
+ // Delete a character
+ if(!strcmp(button_state, "Del")) {
+ if(yes_no("Confirm", "Are you sure?")==0) {
+ // Request character deletion
+ WFIFOW(0) = net_w_value(0x0068);
+ WFIFOL(2) = net_l_value(char_info[0].id);
+ WFIFOSET(46);
+
+ while((in_size<2)||(out_size>0))flush();
+ if(RFIFOW(0)==0x006f) {
+ RFIFOSKIP(2);
+ ok("Info", "Player deleted");
+ free(char_info);
+ n_character = 0;
+ } else if(RFIFOW(0)==0x006c) {
+ switch(RFIFOB(2)) {
+ case 0:
+ ok("Error", "Access denied");
+ break;
+ case 1:
+ ok("Error", "Cannot use this ID");
+ break;
+ }
+ RFIFOSKIP(3);
+ } else ok("Error", "Unknown error");
+ }
+ // Create a new character
+ } else {
+ centre_dialog(char_create_dialog);
+ DIALOG_PLAYER *player = init_dialog(char_create_dialog, -1);
+ int gui_exit = 1;
+ while ((!key[KEY_ESC])&&(gui_exit)) {
+ clear_bitmap(buffer);
+ if(stretch_mode!=0)blit((BITMAP *)graphic[LOGIN_BMP].dat, buffer, 0, 0, 80, 60, 640, 480);
+ else blit((BITMAP *)graphic[LOGIN_BMP].dat, buffer, 0, 0, -120, -90, 640, 480);
+ gui_exit = gui_update(player);
+ blit(buffer, screen, 0, 0, 0, 0, 800, 600);
+ }
+ gui_exit = shutdown_dialog(player);
+ if(gui_exit==3) {
+ WFIFOW(0) = net_w_value(0x0067);
+ strcpy(WFIFOP(2), name);
+ WFIFOB(26) = net_b_value(5);
+ WFIFOB(27) = net_b_value(5);
+ WFIFOB(28) = net_b_value(5);
+ WFIFOB(29) = net_b_value(5);
+ WFIFOB(30) = net_b_value(5);
+ WFIFOB(31) = net_b_value(5);
+ WFIFOB(32) = net_b_value(0);
+ WFIFOW(33) = net_w_value(1);
+ WFIFOW(35) = net_w_value(1);
+ WFIFOSET(37);
+
+ while((in_size<3)||(out_size>0))flush();
+ if(RFIFOW(0)==0x006d) {
+ while(in_size<108)flush();
+ char_info = (CHAR_SEL_INFO *)malloc(sizeof(CHAR_SEL_INFO));
+ char_info->id = account_ID;
+ memset(char_info->name, '\0', 24);
+ strcpy(char_info[0].name, RFIFOP(2+74));
+ char_info->hp = RFIFOW(2+42);
+ char_info->max_hp = RFIFOW(2+44);
+ char_info->sp = RFIFOW(2+46);
+ char_info->max_sp = RFIFOW(2+48);
+ char_info->job_lv = RFIFOL(2+16);
+ char_info->job_xp = RFIFOL(2+12);
+ char_info->lv = RFIFOW(2+58);
+ char_info->xp = RFIFOL(2+4);
+ char_info->zeny = RFIFOL(2+8);
+ char_info->STR = RFIFOB(2+98);
+ char_info->AGI = RFIFOB(2+99);
+ char_info->VIT = RFIFOB(2+100);
+ char_info->INT = RFIFOB(2+101);
+ char_info->DEX = RFIFOB(2+102);
+ char_info->LUK = RFIFOB(2+103);
+ RFIFOSKIP(108);
+ n_character++;
+ } else if(RFIFOW(0)==0x006c) {
+ switch(RFIFOB(2)) {
+ case 0:
+ ok("Error", "Access denied");
+ break;
+ case 1:
+ ok("Error", "Cannot use this ID");
+ break;
+ }
+ RFIFOSKIP(3);
+ } else ok("Error", "Unknown error");
+ }
+ }
+}
diff --git a/src/gui/char_select.h b/src/gui/char_select.h
new file mode 100644
index 00000000..94a8e820
--- /dev/null
+++ b/src/gui/char_select.h
@@ -0,0 +1,41 @@
+/**
+
+ 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
+
+*/
+
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#ifndef _CHAR_SELECT_H
+#define _CHAR_SELECT_H
+
+#include <allegro.h>
+
+#include "../main.h"
+#include "../Net/network.h"
+#include "gui.h"
+
+void char_select();
+void server_char_select();
+void server_char_delete();
+
+#endif
diff --git a/src/gui/char_server.cpp b/src/gui/char_server.cpp
new file mode 100644
index 00000000..36ef5d53
--- /dev/null
+++ b/src/gui/char_server.cpp
@@ -0,0 +1,141 @@
+/**
+
+ 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
+
+*/
+
+#include "char_server.h"
+#include "../Graphic/graphic.h"
+
+char server[30];
+
+DIALOG char_server_dialog[] = {
+ /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
+ { tmw_dialog_proc, 300, 240, 200, 104, 0, -1, 0, 0, 0, 0, (char*)"Server select", NULL, NULL },
+ { tmw_list_proc, 304, 262, 192, 55, 0, 0, 0, 0, 0, 0, (char*)server_list, NULL, NULL },
+ { tmw_button_proc, 398, 322, 44, 18, 0, -1, 'o', D_EXIT, -1, 0, (char*)"&Ok", NULL, NULL },
+ { tmw_button_proc, 446, 322, 44, 18, 0, -1, 'c', D_EXIT, -1, 0, (char*)"&Cancel", NULL, NULL },
+ { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
+};
+
+/** Helper function to create server list */
+char *server_list(int index, int *size) {
+ static char buffer[30];
+ if (index < 0) {
+ *size = n_server;
+ return NULL;
+ }
+ sprintf(buffer, "%s (%i)", server_info[index].name, server_info[index].online_users);
+ return buffer;
+}
+
+void char_server() {
+ state = LOGIN;
+ centre_dialog(char_server_dialog);
+ DIALOG_PLAYER *player = init_dialog(char_server_dialog, -1);
+ if(!player)ok("Error", "Unable to initialize login dialog");
+ int gui_exit = 1;
+ if(n_server==0)char_server_dialog[2].flags |= D_DISABLED;
+ while ((!key[KEY_ESC])&&(gui_exit)&&(!key[KEY_ENTER])) {
+ clear_bitmap(buffer);
+ if(stretch_mode!=0)blit((BITMAP *)graphic[LOGIN_BMP].dat, buffer, 0, 0, 80, 60, 640, 480);
+ else blit((BITMAP *)graphic[LOGIN_BMP].dat, buffer, 0, 0, -120, -90, 640, 480);
+ gui_exit = gui_update(player);
+ blit(buffer, screen, 0, 0, 0, 0, 800, 600);
+ }
+ gui_exit = shutdown_dialog(player);
+ if((gui_exit==2)||(key[KEY_ENTER])) {
+ server_char_server();
+ }
+}
+
+void server_char_server() {
+ int ret;
+ state = LOGIN;
+
+ // Connect to char server
+ ret = open_session(iptostring(server_info[char_server_dialog[1].d1].address), server_info[char_server_dialog[1].d1].port);
+ if(ret==SOCKET_ERROR) {
+ ok("Error", "Unable to connect to char server");
+ return;
+ }
+
+ // Send login infos
+ WFIFOW(0) = net_w_value(0x0065);
+ WFIFOL(2) = net_l_value(account_ID);
+ WFIFOL(6) = net_l_value(session_ID1);
+ WFIFOL(10) = net_l_value(session_ID2);
+ WFIFOW(14) = 0;
+ WFIFOB(16) = net_b_value(sex);
+ WFIFOSET(17);
+
+ while((in_size<4)||(out_size>0))flush();
+ RFIFOSKIP(4);
+
+ while(in_size<3)flush();
+
+ if(RFIFOW(0)==0x006b) {
+ while(in_size<RFIFOW(2))flush();
+ n_character = (RFIFOW(2)-24)/106;
+ char_info = (CHAR_SEL_INFO *)malloc(sizeof(CHAR_SEL_INFO)*n_character);
+ for(int i=0;i<n_character;i++) {
+ char_info[i].id = RFIFOL(24+106*i);
+ strcpy(char_info[i].name, RFIFOP(24+106*i+74));
+ char_info[i].hp = RFIFOW(24+106*i+42);
+ char_info[i].max_hp = RFIFOW(24+106*i+44);
+ char_info[i].xp = RFIFOL(24+106*i+4);
+ char_info[i].zeny = RFIFOL(24+106*i+8);
+ char_info[i].job_xp = RFIFOL(24+106*i+16);
+ char_info[i].job_lv = RFIFOL(24+106*i+24);
+ char_info[i].sp = RFIFOW(24+106*i+46);
+ char_info[i].max_sp = RFIFOW(24+106*i+48);
+ char_info[i].lv = RFIFOW(24+106*i+58);
+ char_info[i].STR = RFIFOB(24+106*i+98);
+ char_info[i].AGI = RFIFOB(24+106*i+99);
+ char_info[i].VIT = RFIFOB(24+106*i+100);
+ char_info[i].INT = RFIFOB(24+106*i+101);
+ char_info[i].DEX = RFIFOB(24+106*i+102);
+ char_info[i].LUK = RFIFOB(24+106*i+103);
+ }
+ state = CHAR_SELECT;
+
+ log("Player", "name", char_info->name);
+ log_hex("Char_Server_Packet", "Packet_ID", RFIFOW(0));
+ log_int("Char_Server_Packet", "Packet_length", RFIFOW(2));
+
+
+ RFIFOSKIP(RFIFOW(2));
+ } else if(RFIFOW(0)==0x006c) {
+ switch(RFIFOB(2)) {
+ case 0:
+ ok("Error", "Access denied");
+ break;
+ case 1:
+ ok("Error", "Cannot use this ID");
+ break;
+ default:
+ ok("Error", "Rejected from server");
+ break;
+ }
+ RFIFOSKIP(3);
+ close_session();
+ } else ok("Error", "Unknown error");
+ // Todo: add other packets
+}
diff --git a/src/gui/char_server.h b/src/gui/char_server.h
new file mode 100644
index 00000000..866f5070
--- /dev/null
+++ b/src/gui/char_server.h
@@ -0,0 +1,41 @@
+/**
+
+ 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
+
+*/
+
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#ifndef _CHAR_SEL_SERVER_H
+#define _CHAR_SEL_SERVER_H
+
+#include <allegro.h>
+
+#include "../main.h"
+#include "../Net/network.h"
+#include "gui.h"
+
+void char_server();
+void server_char_server();
+char *server_list(int index, int *size);
+
+#endif
diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp
new file mode 100644
index 00000000..2f0385c9
--- /dev/null
+++ b/src/gui/chat.cpp
@@ -0,0 +1,303 @@
+/**
+
+ 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
+
+*/
+
+/**
+ Simple ChatLog Object v0.5 (i'd say...)
+
+ Bestviewd w/ Bitstream Vera Sans Mono @ 9pt and a tab-width of 2 spaces
+
+ Author: kth5 aka Alexander Baldeck
+ pipe your questions, suggestions and flames to: kth5@gawab.com
+*/
+
+#include "../main.h"
+#include "chat.h"
+#include <list>
+#include <string>
+#include <fstream>
+
+using namespace std;
+
+
+Chat::Chat(const char * logfile, int item_num) {
+ chatlog_file.open(logfile, ios::out | ios::app);
+ items = 0;
+ items_keep = item_num;
+}
+
+Chat::~Chat() {
+ chatlog_file.flush();
+ chatlog_file.close();
+}
+
+void Chat::chat_dlgrsize(int) {
+}
+
+/** adds a line of text to our message list
+
+ string line -> message text
+ int own -> type of message (usually the owner-type)
+ ALFONT_FONT * font -> font that'll be used to draw the text later
+
+ NOTE:
+ to all of you who wonder why the font needs to be passed, simple.
+ i already store the width in pixel in the list rather than
+ calculating it again and again on every draw event. ;-)
+*/
+void Chat::chat_log(string line, int own, ALFONT_FONT * font) {
+ int pos;
+ CHATLOG tmp;
+
+ if(items<=items_keep)
+ items++; // delete overhead from the end of the list
+ else
+ chatlog.pop_back();
+
+ pos = 0;
+ pos = (int)line.find(" : ", 0);
+ if(pos > 0) {
+ tmp.nick = line.substr(0,pos);
+ switch(own) {
+ case ACT_IS :
+ tmp.nick += CAT_IS;
+ break;
+ case ACT_WHISPER :
+ tmp.nick += CAT_WHISPER;
+ break;
+ default :
+ tmp.nick += CAT_NORMAL;
+ }
+ tmp.width = TEXT_GETWIDTH(tmp.nick.c_str())+2;
+ line.erase(0,pos+3);
+ }else {
+ tmp.nick = "";
+ tmp.width = 1;
+ }
+ tmp.own = own;
+ tmp.text = line;
+
+ chatlog_file << tmp.nick << tmp.text << "\n";
+ chatlog_file.flush();
+
+ chatlog.push_front(tmp);
+}
+
+void Chat::chat_log(CHATSKILL action, ALFONT_FONT * font) {
+ chat_log(const_msg(action), BY_SERVER, font);
+}
+
+
+/** draw first n lines of the list onto a Allegro type bitmap buffer
+ using Alfont
+
+ BITMAP * bmp -> Allegro type bitmap buffer to draw onto
+ int n -> number of lines to be drawn
+ ALFONT_FONT * font -> font to use
+
+ NOTE:
+ take great care using this, make sure the buffer passed is
+ empty! ;-) anyway, line wrapping is not supported yet.
+*/
+void Chat::chat_draw(BITMAP * bmp, int n, ALFONT_FONT * font) {
+ int y = 600-35, i = 0;
+ CHATLOG line;
+ n -= 1;
+
+ for(iter = chatlog.begin(); iter != chatlog.end(); iter++) {
+ line = *iter;
+ y -=11;
+
+ switch(line.own) {
+ case BY_GM :
+ alfont_textprintf_aa(bmp, font, 1, y, COLOR_BLUE, "Global announcement: ");
+ alfont_textprintf_aa(bmp, font, TEXT_GETWIDTH("Global announcement: "), y, COLOR_GREEN, line.text.c_str());
+ break;
+ case BY_PLAYER :
+ alfont_textprintf_aa(bmp, font, 1, y, COLOR_YELLOW, line.nick.c_str());
+ alfont_textprintf_aa(bmp, font, line.width, y, COLOR_WHITE, line.text.c_str());
+ break;
+ case BY_OTHER :
+ alfont_textprintf_aa(bmp, font, 1, y, COLOR_GREEN, line.nick.c_str());
+ alfont_textprintf_aa(bmp, font, line.width, y, COLOR_WHITE, line.text.c_str());
+ break;
+ default :
+ alfont_textprintf_aa(bmp, font, 1, y, COLOR_LIGHTBLUE, line.text.c_str());
+ }
+
+ if(i>=n)
+ return;
+ i++;
+ }
+}
+
+/** determines wether to send a command or an ordinary message, then
+ contructs packets & sends them
+
+ string nick -> the character's name to display infront
+ string msg -> the message's text which is to be send.
+
+ NOTE:
+ the nickname is required by the server, if not specified
+ the message may not be sent unless a command was intended
+ which requires another packet to be constructed! you can
+ achieve this by putting a slash ("/") infront of the
+ message followed by the command name and the message.
+ of course all slash-commands need implemented handler-
+ routines. ;-)
+ remember, a line starting w/ "@" is not a command that needs
+ to be parsed rather is sent using the normal chat-packet.
+
+ EXAMPLE:
+ // for an global announcement /- command
+ chatlog.chat_send("", "/announce Hello to all logged in users!");
+ // for simple message by a user /- message
+ chatlog.chat_send("Zaeiru", "Hello to all users on the screen!");
+*/
+char * Chat::chat_send(string nick, string msg) {
+ short len = 0, packid;
+ char *temp = NULL;
+
+ // prepare command
+ if(msg.substr(0,1)=="/") {
+ // global announcement
+ if(msg.substr(0,IS_ANNOUNCE_LENGTH) == IS_ANNOUNCE) {
+ msg.erase(0,IS_ANNOUNCE_LENGTH);
+ packid = 0x0099;
+ } else {
+ packid = 0x008c;
+ len = (short)msg.length()+4;
+ }
+ len = (short)msg.length()+4;
+ // prepare ordinary message
+ } else {
+ // temporary hack to make messed-up-keyboard-ppl able to send GM commands
+ if(msg.substr(0,1)=="#")
+ msg.replace(0,1,"@");
+ // end temp. hack XD
+ nick += " : ";
+ nick += msg;
+ msg = nick;
+ packid = 0x008c;
+ len = (short)(nick.length()+msg.length()+3);
+ }
+
+ // send processed message
+ temp = new char[len];
+ memcpy(temp, msg.c_str(), len);
+ WFIFOW(0) = net_w_value(packid);
+ WFIFOW(2) = net_w_value(len+4);
+ memcpy(WFIFOP(4), temp, len);
+ WFIFOSET(len+4);
+ delete temp;
+ nick = msg = "";
+ return "";
+}
+
+/** PRIVATE :
+ NOTE:
+ these usually will be left undocumented coz u can't call them
+ directly anyway. ;-)
+*/
+
+/** constructs failed messages for actions */
+string Chat::const_msg(CHATSKILL action) {
+ string msg;
+ if(action.success == SKILL_FAILED && action.skill == SKILL_BASIC) {
+ switch(action.bskill) {
+ case BSKILL_TRADE :
+ msg = "Trade failed!";
+ break;
+ case BSKILL_EMOTE :
+ msg = "Emote failed!";
+ break;
+ case BSKILL_SIT :
+ msg = "Sit failed!";
+ break;
+ case BSKILL_CREATECHAT :
+ msg = "Chat creating failed!";
+ break;
+ case BSKILL_JOINPARTY :
+ msg = "Could not join party!";
+ break;
+ case BSKILL_SHOUT :
+ msg = "Cannot shout!";
+ break;
+ }
+
+ switch(action.reason) {
+ case RFAIL_SKILLDEP :
+ msg += " You have not yet reached a high enough lvl!";
+ break;
+ case RFAIL_INSUFHP :
+ msg += " Insufficient HP!";
+ break;
+ case RFAIL_INSUFSP :
+ msg += " Insufficient SP!";
+ break;
+ case RFAIL_NOMEMO :
+ msg += " You have no memos!";
+ break;
+ case RFAIL_SKILLDELAY :
+ msg += " You cannot do that right now!";
+ break;
+ case RFAIL_ZENY :
+ msg += " Seems you need more Zeny... ;-)";
+ break;
+ case RFAIL_WEAPON :
+ msg += " You cannot use this skill with that kind of weapon!";
+ break;
+ case RFAIL_REDGEM :
+ msg += " You need another red gem!";
+ break;
+ case RFAIL_BLUEGEM :
+ msg += " You need another blue gem!";
+ break;
+ case RFAIL_OVERWEIGHT :
+ msg += " You're carrying to much to do this!";
+ break;
+ default :
+ msg += " Huh? What's that?";
+ break;
+ }
+ }else{
+ switch(action.skill) {
+ case SKILL_WARP :
+ msg = "Warp failed...";
+ break;
+ case SKILL_STEAL :
+ msg = "Could not steal anything...";
+ break;
+ case SKILL_ENVENOM :
+ msg = "Poison had no effect...";
+ break;
+ }
+ }
+
+ return msg;
+}
+
+string const_msg(int own) {
+ string msg;
+ return msg;
+}
+
diff --git a/src/gui/chat.h b/src/gui/chat.h
new file mode 100644
index 00000000..cfe16beb
--- /dev/null
+++ b/src/gui/chat.h
@@ -0,0 +1,150 @@
+/**
+
+ 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
+
+*/
+
+#ifndef _CHAT_H
+#define _CHAT_H
+
+#include "../main.h"
+#include <list>
+#include <string>
+#include <fstream>
+#include <string>
+
+using namespace std;
+
+/**
+ Simple ChatLog Object v0.5 (i'd say...)
+
+ Bestviewd w/ Bitstream Vera Sans Mono @ 9pt and a tab-width of 2 spaces
+
+ Author: kth5 aka Alexander Baldeck
+ pipe your questions, suggestions and flames to: kth5@gawab.com
+
+ NOTE:
+ i documented all functions in their implementation. ;-)
+*/
+
+
+#define BY_GM 0 // those should be self-explanatory =)
+#define BY_PLAYER 1
+#define BY_OTHER 2
+#define BY_SERVER 3
+
+#define ACT_WHISPER 4 // getting whispered at
+#define ACT_IS 5 // equivalent to "/me" in irc
+
+#define IS_ANNOUNCE "/announce "
+#define IS_ANNOUNCE_LENGTH 10
+
+/**
+ gets in between usernick and message text depending on
+ message type
+*/
+#define CAT_NORMAL ": "
+#define CAT_IS ""
+#define CAT_WHISPER " says: "
+
+/** some generic color macros */
+#define COLOR_WHITE (makecol(255,255,255)) // plain white
+#define COLOR_BLUE (makecol( 97,156,236)) // cold gm blue :P
+#define COLOR_YELLOW (makecol(255,246, 98)) // sexy yellow
+#define COLOR_GREEN (makecol( 39,197, 39)) // cool green
+#define COLOR_RED (makecol(255, 0, 0)) // ack red XD
+#define COLOR_LIGHTBLUE (makecol( 83,223,246)) // bright blue
+
+/** calculate text-width in pixel */
+#define TEXT_GETWIDTH(str) (alfont_text_length(font, str))
+
+/** job dependend identifiers (?) */
+#define SKILL_BASIC 0x0001
+#define SKILL_WARP 0x001b
+#define SKILL_STEAL 0x0032
+#define SKILL_ENVENOM 0x0034
+
+/** basic skills identifiers */
+#define BSKILL_TRADE 0x0000
+#define BSKILL_EMOTE 0x0001
+#define BSKILL_SIT 0x0002
+#define BSKILL_CREATECHAT 0x0003
+#define BSKILL_JOINPARTY 0x0004
+#define BSKILL_SHOUT 0x0005
+#define BSKILL_PK 0x0006 // ??
+#define BSKILL_SETALLIGN 0x0007 // ??
+
+/** reasons why action failed */
+#define RFAIL_SKILLDEP 0x00
+#define RFAIL_INSUFHP 0x01
+#define RFAIL_INSUFSP 0x02
+#define RFAIL_NOMEMO 0x03
+#define RFAIL_SKILLDELAY 0x04
+#define RFAIL_ZENY 0x05
+#define RFAIL_WEAPON 0x06
+#define RFAIL_REDGEM 0x07
+#define RFAIL_BLUEGEM 0x08
+#define RFAIL_OVERWEIGHT 0x09
+#define RFAIL_GENERIC 0x0a
+
+/** should always be zero if failed */
+#define SKILL_FAILED 0x00
+
+struct CHATSKILL {
+ short skill;
+ short bskill;
+ short unused;
+ char success;
+ char reason;
+};
+
+class Chat {
+ public :
+ Chat(const char *, int);
+ void chat_dlgrsize(int);
+
+ void chat_log(string, int, ALFONT_FONT *);
+ void chat_log(CHATSKILL, ALFONT_FONT *); // function overload -> calls original chat_log()
+ // after processing the packet
+
+ void chat_draw(BITMAP *, int, ALFONT_FONT *);
+ char * chat_send(string, string);
+ ~Chat();
+ private :
+ ofstream chatlog_file;
+
+ typedef struct CHATLOG { // list item container object
+ string nick;
+ string text;
+ int own;
+ int width;
+ };
+
+ list<CHATLOG> chatlog; // list object ready to accept out CHATLOG struct :)
+ list<CHATLOG>::iterator iter;
+
+ int items;
+ int items_keep;
+
+ string const_msg(CHATSKILL); // contructs action-fail messages
+ string const_msg(int); // constructs normal messages (not implemented yet)
+};
+
+#endif
diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp
new file mode 100644
index 00000000..cb43c47b
--- /dev/null
+++ b/src/gui/gui.cpp
@@ -0,0 +1,1471 @@
+/**
+
+ 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
+
+*/
+
+#include "gui.h"
+#include "allegro/internal/aintern.h"
+#include <math.h>
+#include <alfont.h>
+#include "../Sound/sound.h"
+
+#ifndef WIN32
+#define __cdecl __attribute__((cdecl))
+#endif
+
+#define GUI_BMP_COUNT 11
+#define GUI_BMP_OFS_BUTTON 0
+#define GUI_BMP_OFS_SLIDER 4
+#define GUI_BMP_OFS_CHECKBOX 5
+#define GUI_BMP_OFS_RADIOBUTTON 6
+#define GUI_BMP_OFS_TEXTBOX 7
+#define GUI_BMP_OFS_LISTBOX 8
+#define GUI_BMP_OFS_DIALOG 9
+
+#define GUI_CALL_BUTTONCALLBACK(d)
+static BITMAP *gui__repository[GUI_BMP_COUNT];
+
+/* The currently active skin */
+LexSkin gui_skin;
+BITMAP *gui_bitmap;
+ALFONT_FONT *gui_font;
+bool drag;
+DATAFILE *gui_gfx;
+
+extern TmwSound sound;
+
+/* very internal update stuff */
+int (*gui__external_slider_callback)(void *, int);
+int reroute_slider_proc(void *dp3, int d2);
+
+/** Initialize gui system */
+void init_gui(BITMAP *bitmap, const char *skin) {
+ gui_bitmap = bitmap;
+ gui_load_skin(skin);
+ //alfont_init();
+ gui_font = alfont_load_font("./data/skin/arial.ttf");
+ alfont_set_font_size(gui_font, 14);
+ drag = false;
+ show_mouse(NULL);
+}
+
+int gui_update(DIALOG_PLAYER *player) {
+ dialog_message(player->dialog, MSG_DRAW, 0, 0);
+ int ret = update_dialog(player);
+ draw_sprite(gui_bitmap, mouse_sprite, mouse_x, mouse_y);
+ return ret;
+}
+
+
+void loadButtonSkin() {
+ char **tokens;
+ int tokenCount;
+ int gridx[4];
+ int gridy[4];
+ int a = 0;
+ int x,y,mode;
+
+ tokens = get_config_argv("button", "gridx", &tokenCount);
+ for (a=0; a < 4; a++) {
+ gridx[a] = atoi(tokens[a]);
+ }
+ tokens = get_config_argv("button", "gridy", &tokenCount);
+ for (a=0; a < 4; a++) {
+ gridy[a] = atoi(tokens[a]);
+ }
+
+ tokens = get_config_argv("button", "textcol_norm", &tokenCount);
+ gui_skin.button.textcolor[0] = makecol(atoi(tokens[0]),atoi(tokens[1]),atoi(tokens[2]));
+ tokens = get_config_argv("button", "textcol_hilite", &tokenCount);
+ gui_skin.button.textcolor[1] = makecol(atoi(tokens[0]),atoi(tokens[1]),atoi(tokens[2]));
+ tokens = get_config_argv("button", "textcol_pressed", &tokenCount);
+ gui_skin.button.textcolor[2] = makecol(atoi(tokens[0]),atoi(tokens[1]),atoi(tokens[2]));
+ tokens = get_config_argv("button", "textcol_disabled", &tokenCount);
+ gui_skin.button.textcolor[3] = makecol(atoi(tokens[0]),atoi(tokens[1]),atoi(tokens[2]));
+
+ gui__repository[GUI_BMP_OFS_BUTTON + 0] = (BITMAP *)gui_gfx[0].dat;
+ gui__repository[GUI_BMP_OFS_BUTTON + 1] = (BITMAP *)gui_gfx[2].dat;
+ gui__repository[GUI_BMP_OFS_BUTTON + 2] = (BITMAP *)gui_gfx[3].dat;
+ gui__repository[GUI_BMP_OFS_BUTTON + 3] = (BITMAP *)gui_gfx[1].dat;
+
+ for (mode=0; mode < 4; mode++) {
+ a=0;
+ for (y=0; y < 3; y++) {
+ for (x=0; x < 3; x++) {
+ gui_skin.button.background[mode].grid[a] = create_sub_bitmap(
+ gui__repository[GUI_BMP_OFS_BUTTON + mode],
+ gridx[x] , gridy[y],
+ gridx[x+1]-gridx[x]+1, gridy[y+1]-gridy[y]+1
+ );
+ a++;
+ }
+ }
+ }
+}
+
+
+void loadSliderSkin() {
+ int x, y, w, h,o1,o2;
+ char **tokens;
+ int tokenCount;
+
+ gui__repository[GUI_BMP_OFS_SLIDER] = (BITMAP *)gui_gfx[8].dat;
+
+ tokens = get_config_argv("slider", "slider_h", &tokenCount);
+ x = atoi(tokens[0]); y = atoi(tokens[1]);
+ w = atoi(tokens[2]); h = atoi(tokens[3]);
+
+ tokens = get_config_argv("slider", "slider_h_ofs", &tokenCount);
+ o1 = atoi(tokens[0]); o2 = atoi(tokens[1]);
+
+ gui_skin.slider.hSlider[0] = create_sub_bitmap(gui__repository[GUI_BMP_OFS_SLIDER], x , y, o1-x , h);
+ gui_skin.slider.hSlider[1] = create_sub_bitmap(gui__repository[GUI_BMP_OFS_SLIDER], o1, y, o2-o1 , h);
+ gui_skin.slider.hSlider[2] = create_sub_bitmap(gui__repository[GUI_BMP_OFS_SLIDER], o2, y, w-(o2-x), h);
+
+ tokens = get_config_argv("slider", "slider_v", &tokenCount);
+ x = atoi(tokens[0]); y = atoi(tokens[1]);
+ w = atoi(tokens[2]); h = atoi(tokens[3]);
+
+ tokens = get_config_argv("slider", "slider_v_ofs", &tokenCount);
+ o1 = atoi(tokens[0]); o2 = atoi(tokens[1]);
+
+ gui_skin.slider.vSlider[0] = create_sub_bitmap(gui__repository[GUI_BMP_OFS_SLIDER], x, y, w, o1 - y);
+ gui_skin.slider.vSlider[1] = create_sub_bitmap(gui__repository[GUI_BMP_OFS_SLIDER], x, o1, w, o2 - o1);
+ gui_skin.slider.vSlider[2] = create_sub_bitmap(gui__repository[GUI_BMP_OFS_SLIDER], x, o2, w, h - (o2-y));
+
+ tokens = get_config_argv("slider", "handle_v", &tokenCount);
+ x = atoi(tokens[0]); y = atoi(tokens[1]);
+ w = atoi(tokens[2]); h = atoi(tokens[3]);
+ gui_skin.slider.vGrip = create_sub_bitmap(gui__repository[GUI_BMP_OFS_SLIDER], x, y, w, h);
+
+ tokens = get_config_argv("slider", "handle_h", &tokenCount);
+ x = atoi(tokens[0]); y = atoi(tokens[1]);
+ w = atoi(tokens[2]); h = atoi(tokens[3]);
+ gui_skin.slider.hGrip = create_sub_bitmap(gui__repository[GUI_BMP_OFS_SLIDER], x, y, w, h);
+}
+
+void loadCheckboxSkin() {
+ int x, y, w,h;
+ char **tokens;
+ int tokenCount;
+
+ gui__repository[GUI_BMP_OFS_CHECKBOX] = (BITMAP *)gui_gfx[4].dat;
+
+
+ tokens = get_config_argv("checkbox", "normal", &tokenCount);
+ x = atoi(tokens[0]); y = atoi(tokens[1]);
+ w = atoi(tokens[2]); h = atoi(tokens[3]);
+ gui_skin.checkbox.normal = create_sub_bitmap(gui__repository[GUI_BMP_OFS_CHECKBOX], x , y, w, h);
+
+ tokens = get_config_argv("checkbox", "checked", &tokenCount);
+ x = atoi(tokens[0]); y = atoi(tokens[1]);
+ w = atoi(tokens[2]); h = atoi(tokens[3]);
+ gui_skin.checkbox.checked = create_sub_bitmap(gui__repository[GUI_BMP_OFS_CHECKBOX], x , y, w, h);
+
+ tokens = get_config_argv("checkbox", "disabled", &tokenCount);
+ x = atoi(tokens[0]); y = atoi(tokens[1]);
+ w = atoi(tokens[2]); h = atoi(tokens[3]);
+ gui_skin.checkbox.disabled = create_sub_bitmap(gui__repository[GUI_BMP_OFS_CHECKBOX], x , y, w, h);
+
+ tokens = get_config_argv("checkbox", "disabled_check", &tokenCount);
+ x = atoi(tokens[0]); y = atoi(tokens[1]);
+ w = atoi(tokens[2]); h = atoi(tokens[3]);
+ gui_skin.checkbox.disabled_checked = create_sub_bitmap(gui__repository[GUI_BMP_OFS_CHECKBOX], x , y, w, h);
+
+ tokens = get_config_argv("button", "textcol_norm", &tokenCount);
+ gui_skin.checkbox.textcolor[0] = makecol(atoi(tokens[0]),atoi(tokens[1]),atoi(tokens[2]));
+ tokens = get_config_argv("button", "textcol_disabled", &tokenCount);
+ gui_skin.checkbox.textcolor[1] = makecol(atoi(tokens[0]),atoi(tokens[1]),atoi(tokens[2]));
+}
+
+void loadTextboxSkin() {
+ char **tokens;
+ int tokenCount;
+ int gridx[4];
+ int gridy[4];
+ int a = 0;
+ int x,y;
+
+ tokens = get_config_argv("textbox", "gridx", &tokenCount);
+ for (a=0; a < 4; a++) {
+ gridx[a] = atoi(tokens[a]);
+ }
+ tokens = get_config_argv("textbox", "gridy", &tokenCount);
+ for (a=0; a < 4; a++) {
+ gridy[a] = atoi(tokens[a]);
+ }
+
+ tokens = get_config_argv("textbox", "textcol_norm", &tokenCount);
+ gui_skin.textbox.textcolor[0] = makecol(atoi(tokens[0]),atoi(tokens[1]),atoi(tokens[2]));
+ tokens = get_config_argv("textbox", "textcol_disabled", &tokenCount);
+ gui_skin.textbox.textcolor[1] = makecol(atoi(tokens[0]),atoi(tokens[1]),atoi(tokens[2]));
+
+ gui__repository[GUI_BMP_OFS_TEXTBOX] = (BITMAP *)gui_gfx[9].dat;
+
+
+
+ a=0;
+ for (y=0; y < 3; y++) {
+ for (x=0; x < 3; x++) {
+ gui_skin.textbox.bg.grid[a] = create_sub_bitmap(
+ gui__repository[GUI_BMP_OFS_TEXTBOX],
+ gridx[x] , gridy[y],
+ gridx[x+1]-gridx[x]+1, gridy[y+1]-gridy[y]+1
+ );
+ a++;
+ }
+ }
+}
+
+void loadListboxSkin() {
+ char **tokens;
+ int tokenCount;
+ int gridx[4];
+ int gridy[4];
+ int a = 0;
+ int x,y;
+
+ tokens = get_config_argv("listbox", "gridx", &tokenCount);
+ for (a=0; a < 4; a++) {
+ gridx[a] = atoi(tokens[a]);
+ }
+ tokens = get_config_argv("listbox", "gridy", &tokenCount);
+ for (a=0; a < 4; a++) {
+ gridy[a] = atoi(tokens[a]);
+ }
+
+ tokens = get_config_argv("listbox", "textcol_norm", &tokenCount);
+ gui_skin.listbox.textcolor[0] = makecol(atoi(tokens[0]),atoi(tokens[1]),atoi(tokens[2]));
+ tokens = get_config_argv("listbox", "textcol_selected", &tokenCount);
+ gui_skin.listbox.textcolor[1] = makecol(atoi(tokens[0]),atoi(tokens[1]),atoi(tokens[2]));
+ tokens = get_config_argv("listbox", "textbg_selected", &tokenCount);
+ gui_skin.listbox.textcolor[2] = makecol(atoi(tokens[0]),atoi(tokens[1]),atoi(tokens[2]));
+ tokens = get_config_argv("listbox", "textcol_disabled", &tokenCount);
+ gui_skin.listbox.textcolor[3] = makecol(atoi(tokens[0]),atoi(tokens[1]),atoi(tokens[2]));
+
+ gui__repository[GUI_BMP_OFS_LISTBOX+0] = (BITMAP *)gui_gfx[6].dat;
+ gui__repository[GUI_BMP_OFS_LISTBOX+1] = (BITMAP *)gui_gfx[10].dat;
+
+ a=0;
+ for (y=0; y < 3; y++) {
+ for (x=0; x < 3; x++) {
+ gui_skin.listbox.bg.grid[a] = create_sub_bitmap(
+ gui__repository[GUI_BMP_OFS_LISTBOX],
+ gridx[x] , gridy[y],
+ gridx[x+1]-gridx[x]+1, gridy[y+1]-gridy[y]+1
+ );
+ a++;
+ }
+ }
+
+ tokens = get_config_argv("listbox", "vscroll_gridx", &tokenCount);
+ for (a=0; a < 4; a++) {
+ gridx[a] = atoi(tokens[a]);
+ }
+ tokens = get_config_argv("listbox", "vscroll_gridy", &tokenCount);
+ for (a=0; a < 4; a++) {
+ gridy[a] = atoi(tokens[a]);
+ }
+ a=0;
+ for (y=0; y < 3; y++) {
+ for (x=0; x < 3; x++) {
+ gui_skin.listbox.vscroll.grid[a] = create_sub_bitmap(
+ gui__repository[GUI_BMP_OFS_LISTBOX+1],
+ gridx[x] , gridy[y],
+ gridx[x+1]-gridx[x]+1, gridy[y+1]-gridy[y]+1
+ );
+ a++;
+ }
+ }
+
+}
+
+void loadDialogSkin() {
+ char **tokens;
+ int tokenCount;
+ int gridx[4];
+ int gridy[4];
+ int a = 0;
+ int x,y;
+
+ tokens = get_config_argv("dialog", "gridx", &tokenCount);
+ for (a=0; a < 4; a++) {
+ gridx[a] = atoi(tokens[a]);
+ }
+ tokens = get_config_argv("dialog", "gridy", &tokenCount);
+ for (a=0; a < 4; a++) {
+ gridy[a] = atoi(tokens[a]);
+ }
+
+ gui__repository[GUI_BMP_OFS_DIALOG] = (BITMAP *)gui_gfx[5].dat;
+
+ a=0;
+ for (y=0; y < 3; y++) {
+ for (x=0; x < 3; x++) {
+ gui_skin.dialog.bg.grid[a] = create_sub_bitmap(
+ gui__repository[GUI_BMP_OFS_DIALOG],
+ gridx[x] , gridy[y],
+ gridx[x+1]-gridx[x]+1, gridy[y+1]-gridy[y]+1
+ );
+ a++;
+ }
+ }
+}
+
+void drawSkinnedRect(BITMAP*dst, LexSkinnedRect *skin, int x, int y,int w, int h) {
+
+ BITMAP **grid = skin->grid;
+
+ int w0 = grid[0]->w;
+ int w1 = w - grid[0]->w -grid[2]->w;
+ int w2 = grid[2]->w;
+ int h0 = grid[0]->h;
+ int h1 = h - grid[0]->h - grid[6]->h;
+ int h2 = grid[6]->h;
+
+ int cx,cy;
+
+ cx = x; cy = y;
+ masked_blit(grid[0], dst, 0, 0, cx, cy,grid[0]->w,grid[0]->h);
+ cy += h0;
+ masked_stretch_blit(grid[3], dst, 0, 0, grid[3]->w,grid[3]->h,cx, cy,w0,h1);
+ cy += h1;
+ masked_blit(grid[6], dst, 0, 0, cx, cy,grid[6]->w,grid[6]->h);
+
+ cx += w0;
+ cy = y;
+ masked_stretch_blit(grid[1], dst, 0, 0, grid[1]->w,grid[1]->h,cx, cy,w1,h0);
+ cy += h0;
+ masked_stretch_blit(grid[4], dst, 0, 0, grid[4]->w,grid[4]->h,cx, cy,w1,h1);
+ cy += h1;
+ masked_stretch_blit(grid[7], dst, 0, 0, grid[7]->w,grid[7]->h,cx, cy,w1,h2);
+
+ cx += w1;
+ cy = y;
+ masked_blit(grid[2], dst, 0, 0, cx, cy,grid[2]->w,grid[2]->h);
+ cy += h0;
+ masked_stretch_blit(grid[5], dst, 0, 0, grid[5]->w,grid[5]->h,cx, cy,w2,h1);
+ cy += h1;
+ masked_blit(grid[8], dst, 0, 0, cx, cy,grid[8]->w,grid[7]->h);
+}
+
+
+int gui_load_skin(const char* skinname) {
+ gui__external_slider_callback = NULL;
+ push_config_state();
+ set_config_file(skinname);
+ gui_gfx = load_datafile(get_config_string("skin", "gfx", 0));
+ loadButtonSkin();
+ loadSliderSkin();
+ loadCheckboxSkin();
+ loadTextboxSkin();
+ loadListboxSkin();
+ loadDialogSkin();
+ pop_config_state();
+ set_mouse_sprite((BITMAP *)gui_gfx[7].dat);
+
+ return TRUE;
+}
+
+void gui_exit() {
+ //alfont_destroy_font(gui_font);
+ gui_shutdown();
+ //alfont_exit();
+}
+
+void gui_shutdown(void) {
+ int a, b;
+
+ /* Button */
+ for (a=0; a < 3; a++) {
+ for (b=0; b < 9 ; b++) {
+ destroy_bitmap(gui_skin.button.background[a].grid[b]);
+ }
+
+ }
+ /* Slider */
+ for (a=0; a < 3; a++) {
+ destroy_bitmap(gui_skin.slider.hSlider[a]);
+ destroy_bitmap(gui_skin.slider.vSlider[a]);
+ }
+ destroy_bitmap(gui_skin.slider.hGrip);
+ destroy_bitmap(gui_skin.slider.vGrip);
+
+ /* Checkbox */
+ destroy_bitmap(gui_skin.checkbox.normal);
+ destroy_bitmap(gui_skin.checkbox.checked);
+ destroy_bitmap(gui_skin.checkbox.disabled);
+ destroy_bitmap(gui_skin.checkbox.disabled_checked);
+
+ /* Radiobutton */
+ destroy_bitmap(gui_skin.radiobutton.normal);
+ destroy_bitmap(gui_skin.radiobutton.checked);
+ destroy_bitmap(gui_skin.radiobutton.disabled);
+ destroy_bitmap(gui_skin.radiobutton.disabled_checked);
+
+ for (a=0; a < GUI_BMP_COUNT; a++) {
+ destroy_bitmap(gui__repository[a]);
+ }
+}
+
+/** Draw text for gui widgets */
+int gui_text(BITMAP *bmp, AL_CONST char *s, int x, int y, int color, int centre) {
+ char tmp[1024];
+ int hline_pos = -1;
+ int len = 0;
+ int in_pos = 0;
+ int out_pos = 0;
+ int pix_len, c;
+
+ while (((c = ugetc(s+in_pos)) != 0) && (out_pos<(int)(sizeof(tmp)-ucwidth(0)))) {
+ if (c == '&') {
+ in_pos += uwidth(s+in_pos);
+ c = ugetc(s+in_pos);
+ if (c == '&') {
+ out_pos += usetc(tmp+out_pos, '&');
+ in_pos += uwidth(s+in_pos);
+ len++;
+ } else hline_pos = len;
+ } else {
+ out_pos += usetc(tmp+out_pos, c);
+ in_pos += uwidth(s+in_pos);
+ len++;
+ }
+ }
+ usetc(tmp+out_pos, 0);
+ pix_len = alfont_text_length(gui_font, tmp);
+
+ if (centre)x -= pix_len / 2;
+ if (bmp) {
+ alfont_textout_aa(bmp, gui_font, tmp, x, y, color);
+ if (hline_pos >= 0) {
+ c = ugetat(tmp, hline_pos);
+ usetat(tmp, hline_pos, 0);
+ hline_pos = alfont_text_length(gui_font, tmp);
+ c = usetc(tmp, c);
+ usetc(tmp+c, 0);
+ c = alfont_text_length(gui_font, tmp);
+ hline(bmp, x+hline_pos, y+alfont_text_height(gui_font)-gui_font_baseline, x+hline_pos+c-1, color);
+ }
+ }
+ return pix_len;
+}
+
+int tmw_text_proc(int msg, DIALOG *d, int c) {
+ if (msg==MSG_DRAW) {
+ int rtm;
+ rtm = alfont_text_mode(-1);
+ gui_text(gui_bitmap, (char *)d->dp, d->x, d->y, d->fg, FALSE);
+ alfont_text_mode(rtm);
+ }
+ return D_O_K;
+}
+
+
+int tmw_button_proc(int msg, DIALOG *d, int c) {
+
+ int rtm = 0;
+ int col = 0;
+ int ofs = 0;
+ int ret = D_O_K;
+
+ if (msg == MSG_DRAW) {
+ rectfill(gui_bitmap, d->x, d->y, d->x + d->w, d->y+d->h, makecol(255,255,255));
+
+ if (d->flags & D_DISABLED) {
+ drawSkinnedRect(gui_bitmap, &gui_skin.button.background[3], d->x, d->y, d->w, d->h);
+ col = gui_skin.button.textcolor[3];
+ } else if (d->flags & D_SELECTED) {
+ drawSkinnedRect(gui_bitmap, &gui_skin.button.background[2], d->x, d->y, d->w, d->h);
+ col = gui_skin.button.textcolor[2];
+ ofs = 1;
+ } else if (d->flags & D_GOTMOUSE) {
+ drawSkinnedRect(gui_bitmap, &gui_skin.button.background[1], d->x, d->y, d->w, d->h);
+ col = gui_skin.button.textcolor[1];
+ } else {
+ drawSkinnedRect(gui_bitmap, &gui_skin.button.background[0], d->x, d->y, d->w, d->h);
+ col = gui_skin.button.textcolor[0];
+ }
+ rtm = alfont_text_mode(-1);
+ gui_text(gui_bitmap, (const char *)d->dp, d->x+d->w/2+ofs, d->y+d->h/2-alfont_text_height(gui_font)/2+ofs, col, TRUE);
+ alfont_text_mode(rtm);
+ ret = D_O_K;
+ } else {
+ ret = d_button_proc(msg,d,c);
+ }
+ return ret;
+}
+
+int tmw_slider_proc(int msg, DIALOG *d, int c) {
+ int w = 0;
+ int h = 0;
+ int x,y;
+
+ int ret = D_O_K;
+
+ static int watchdog = 0;
+
+ watchdog++;
+ if (watchdog == 1) {
+ gui__external_slider_callback = (int(__cdecl *)(void *, int))d->dp2;
+ d->dp2 = (void*)reroute_slider_proc;
+ }
+
+ if (msg == MSG_DRAW) {
+ if (d->w >= d->h) {
+ rectfill(gui_bitmap, d->x, d->y, d->x + d->w, d->y+d->h, d->bg);
+ /* horiz */
+ x = d->x;
+ y = d->y + (d->h- gui_skin.slider.hSlider[0]->h)/2;
+ masked_blit(gui_skin.slider.hSlider[0], gui_bitmap, 0, 0, x, y, gui_skin.slider.hSlider[0]->w, gui_skin.slider.hSlider[0]->h);
+ w = d->w -gui_skin.slider.hSlider[0]->w - gui_skin.slider.hSlider[2]->w;
+ x+= gui_skin.slider.hSlider[0]->w;
+
+ masked_stretch_blit(
+ gui_skin.slider.hSlider[1], gui_bitmap,
+ 0, 0, gui_skin.slider.hSlider[1]->w, gui_skin.slider.hSlider[1]->h,
+ x, y, w, gui_skin.slider.hSlider[1]->h);
+
+ x+=w;
+ masked_blit(gui_skin.slider.hSlider[2], gui_bitmap, 0, 0, x, y, gui_skin.slider.hSlider[2]->w, gui_skin.slider.hSlider[2]->h);
+
+ x = d->x + ((d->w-gui_skin.slider.hGrip->w) * d->d2)/d->d1;
+ y = d->y + (d->h - gui_skin.slider.hGrip->h)/2;
+ masked_blit(gui_skin.slider.hGrip, gui_bitmap, 0, 0, x, y, gui_skin.slider.hGrip->w, gui_skin.slider.hGrip->h);
+ } else {
+ rectfill(gui_bitmap, d->x, d->y, d->x + d->w, d->y+d->h, d->bg);
+ /* vertic */
+ x = d->x+ (d->w- gui_skin.slider.vSlider[0]->w)/2;
+ y = d->y;
+ masked_blit(gui_skin.slider.vSlider[0], gui_bitmap, 0, 0, x, y, gui_skin.slider.vSlider[0]->w, gui_skin.slider.vSlider[0]->h);
+ h = d->h - gui_skin.slider.vSlider[0]->h - gui_skin.slider.vSlider[2]->h;
+ y += gui_skin.slider.vSlider[0]->h;
+
+ masked_stretch_blit(
+ gui_skin.slider.vSlider[1], gui_bitmap,
+ 0, 0, gui_skin.slider.vSlider[1]->w, gui_skin.slider.vSlider[1]->h,
+ x, y, gui_skin.slider.vSlider[1]->w, h);
+
+ y+=h;
+ masked_blit(gui_skin.slider.vSlider[2], gui_bitmap, 0, 0, x, y, gui_skin.slider.vSlider[2]->w, gui_skin.slider.vSlider[2]->h);
+
+ y = d->y + d->h - (((d->h-gui_skin.slider.vGrip->h) * d->d2)/d->d1)-gui_skin.slider.vGrip->h;
+ x = d->x + (d->w - gui_skin.slider.vGrip->w)/2;
+ if (gui_skin.slider.vGrip->w % 2 !=0) {
+ x++;
+ }
+ masked_blit(gui_skin.slider.vGrip, gui_bitmap, 0, 0, x, y, gui_skin.slider.vGrip->w, gui_skin.slider.vGrip->h);
+ }
+ //textprintf(gui_bitmap, gui_font,10, 10, makecol(255,255,255), "%i", d->d2);
+ } else {
+ ret = d_slider_proc(msg,d,c);
+ }
+ if (watchdog == 1) {
+ d->dp2 = (void*)gui__external_slider_callback;
+ }
+ watchdog--;
+ return ret;
+}
+
+int tmw_check_proc(int msg, DIALOG *d, int c) {
+ BITMAP *box = NULL;
+ int x, y;
+ int tx, ty, l;
+ int rtm = 0;
+ int col = 0;
+ if (msg == MSG_DRAW) {
+// rectfill(gui_bitmap, d->x, d->y, d->x + d->w, d->y+d->h, d->bg);
+ if (d->flags & D_SELECTED) {
+ if (d->flags & D_DISABLED) {
+ box = gui_skin.checkbox.disabled_checked;
+ } else {
+ box = gui_skin.checkbox.checked;
+ }
+ } else if (d->flags & D_DISABLED) {
+ box = gui_skin.checkbox.disabled;
+ } else {
+ box = gui_skin.checkbox.normal;
+ }
+
+ if (d->flags & D_DISABLED) {
+ col = gui_skin.checkbox.textcolor[1];
+ } else {
+ col = gui_skin.checkbox.textcolor[0];
+ }
+
+ if (d->dp != NULL) {
+ l = gui_strlen((const char *)d->dp);
+ } else {
+ l = 0;
+ }
+
+ if (d->d1 != 0) {
+ x = d->x;
+ tx = x + box->w + box->w/2;
+ } else {
+ x = d->x + d->w - box->w;
+ tx = x - box->w/2 - l;
+ }
+ y = d->y + (d->h - box->h)/ 2;
+ ty = d->y + (d->h - alfont_text_height(gui_font)) / 2;
+
+ masked_blit(box, gui_bitmap, 0, 0, x, y, box->w, box->h);
+ if (d->dp != NULL) {
+ rtm = alfont_text_mode(-1);
+ gui_text(gui_bitmap, (const char *)d->dp, tx, ty, col, 0);
+ alfont_text_mode(rtm);
+ }
+
+
+ } else {
+ return d_check_proc(msg, d, c);
+ }
+ return D_O_K;
+}
+
+int tmw_radio_proc(int msg, DIALOG *d, int c) {
+ BITMAP *box = NULL;
+ int x, y;
+ int tx, ty, l;
+ int rtm = 0;
+ int col = 0;
+
+
+ if (msg == MSG_DRAW) {
+ rectfill(gui_bitmap, d->x, d->y, d->x + d->w, d->y+d->h, d->bg);
+ if (d->flags & D_SELECTED) {
+ if (d->flags & D_DISABLED) {
+ box = gui_skin.radiobutton.disabled_checked;
+ } else {
+ box = gui_skin.radiobutton.checked;
+ }
+ } else if (d->flags & D_DISABLED) {
+ box = gui_skin.radiobutton.disabled;
+ } else {
+ box = gui_skin.radiobutton.normal;
+ }
+
+ if (d->flags & D_DISABLED) {
+ col = gui_skin.radiobutton.textcolor[1];
+ } else {
+ col = gui_skin.radiobutton.textcolor[0];
+ }
+
+ if (d->dp != NULL) {
+ l = gui_strlen((const char *)d->dp);
+ } else {
+ l = 0;
+ }
+
+ if (d->d2 != 0) {
+ x = d->x;
+ tx = x + box->w + box->w/2;
+ } else {
+ x = d->x + d->w - box->w;
+ tx = x - box->w/2 - l;
+ }
+ y = d->y + (d->h - box->h)/ 2;
+ ty = d->y + (d->h - alfont_text_height(gui_font)) / 2;
+
+ masked_blit(box, gui_bitmap, 0, 0, x, y, box->w, box->h);
+ if (d->dp != NULL) {
+ rtm = alfont_text_mode(-1);
+ gui_text(gui_bitmap, (const char *)d->dp, tx, ty, col, 0);
+ alfont_text_mode(rtm);
+ }
+
+
+ } else {
+ return d_radio_proc(msg, d, c);
+ }
+ return D_O_K;
+}
+
+int tmw_edit_proc(int msg, DIALOG *d, int c) {
+// BITMAP *box = NULL;
+ int x;
+ int tx, ty, l;
+ int rtm = 0;
+ int col = 0;
+ char* start;
+ char* text;
+ char hack;
+ int cl, cr, cb, ct;
+ int lb, rb;
+
+
+ if (msg == MSG_DRAW) {
+ rectfill(gui_bitmap, d->x, d->y, d->x + d->w, d->y+d->h, d->bg);
+ drawSkinnedRect(gui_bitmap, &gui_skin.textbox.bg, d->x, d->y, d->w, d->h);
+
+ if (d->flags & D_DISABLED) {
+ col = gui_skin.textbox.textcolor[1];
+ } else {
+ col = gui_skin.textbox.textcolor[0];
+ }
+
+ lb = gui_skin.textbox.bg.grid[0]->w;
+ rb = gui_skin.textbox.bg.grid[2]->w;
+ tx = d->x + lb;
+ ty = d->y + (d->h - alfont_text_height(gui_font))/2;
+
+
+ text = (char *)d->dp;
+ start = text;
+
+ rtm = alfont_text_mode(-1);
+
+ if (gui_bitmap->clip) {
+ cl = gui_bitmap->cl;
+ ct = gui_bitmap->ct;
+ cr = gui_bitmap->cr;
+ cb = gui_bitmap->cb;
+ } else {
+ cl=ct=0;
+ cr=gui_bitmap->w;
+ cb=gui_bitmap->h;
+ }
+ set_clip_rect(gui_bitmap, tx, ty, d->x+d->w-rb, ty + alfont_text_height(gui_font)); // set_clip() is deprecated use set_clip_rect() instead
+ hack = text[d->d2];
+ text[d->d2] = '\0';
+ l = alfont_text_length(gui_font, text);
+ text[d->d2] = hack;
+
+ if (l > d->w-lb-rb) {
+ tx += ((d->w-lb-rb) - l);
+ }
+ gui_text(gui_bitmap, start, tx, ty, col, 0);
+
+
+ if (d->flags & D_GOTFOCUS) {
+ hack = text[d->d2];
+ text[d->d2] = '\0';
+ x = tx + alfont_text_length(gui_font, text);
+ vline(gui_bitmap, x, ty, ty + alfont_text_height(gui_font), col);
+ text[d->d2] = hack;
+ }
+ alfont_text_mode(rtm);
+ set_clip_rect(gui_bitmap, cl, ct, cr, cb);
+ } else {
+ return d_edit_proc(msg, d, c);
+ }
+ return D_O_K;
+}
+
+int tmw_password_proc(int msg, DIALOG *d, int c) {
+// BITMAP *box = NULL;
+ int x;
+ int tx, ty, l;
+ int rtm = 0;
+ int col = 0;
+ char* start;
+ char* text;
+ char hack;
+ int cl, cr, cb, ct;
+ int lb, rb;
+
+
+ if (msg == MSG_DRAW) {
+ rectfill(gui_bitmap, d->x, d->y, d->x + d->w, d->y+d->h, d->bg);
+ drawSkinnedRect(gui_bitmap, &gui_skin.textbox.bg, d->x, d->y, d->w, d->h);
+
+ if (d->flags & D_DISABLED) {
+ col = gui_skin.textbox.textcolor[1];
+ } else {
+ col = gui_skin.textbox.textcolor[0];
+ }
+
+ lb = gui_skin.textbox.bg.grid[0]->w;
+ rb = gui_skin.textbox.bg.grid[2]->w;
+ tx = d->x + lb;
+ ty = d->y + (d->h - alfont_text_height(gui_font))/2;
+
+
+ text = (char *)malloc(strlen((char *)d->dp)+1);
+ // Sull: new ansi standard
+ unsigned int i;
+ for(i=0;i<strlen((char *)d->dp);i++)text[i] = '*';
+ text[i] = '\0';
+ start = text;
+
+ rtm = alfont_text_mode(-1);
+
+ if (gui_bitmap->clip) {
+ cl = gui_bitmap->cl;
+ ct = gui_bitmap->ct;
+ cr = gui_bitmap->cr;
+ cb = gui_bitmap->cb;
+ } else {
+ cl=ct=0;
+ cr=gui_bitmap->w;
+ cb=gui_bitmap->h;
+ }
+ set_clip_rect(gui_bitmap, tx, ty, d->x+d->w-rb, ty + alfont_text_height(gui_font));
+
+ hack = text[d->d2];
+ text[d->d2] = '\0';
+ l = alfont_text_length(gui_font, text);
+ text[d->d2] = hack;
+
+ if (l > d->w-lb-rb) {
+ tx += ((d->w-lb-rb) - l);
+ }
+ gui_text(gui_bitmap, start, tx, ty, col, 0);
+
+
+ if (d->flags & D_GOTFOCUS) {
+ hack = text[d->d2];
+ text[d->d2] = '\0';
+ x = tx + alfont_text_length(gui_font, text);
+ vline(gui_bitmap, x, ty, ty + alfont_text_height(gui_font), col);
+ text[d->d2] = hack;
+ }
+ alfont_text_mode(rtm);
+ set_clip_rect(gui_bitmap, cl, ct, cr, cb);
+ } else {
+ return d_edit_proc(msg, d, c);
+ }
+ return D_O_K;
+}
+
+int tmw_list_proc(int msg, DIALOG *d, int c) {
+// BITMAP *box = NULL;
+
+ static int ignoreRedraw = FALSE;
+
+ int itemCount = 0;
+ int firstItem = d->d2;
+ int lastItem = 0;
+ int selectedItem = d->d1;
+ int x,y,delta;
+ int a, col;
+ int w, h = 0;
+ int rtm = 0;
+ int cl, cr, cb, ct;
+ int th = alfont_text_height(gui_font);
+
+ int vscroll = 0;
+ int sliderh = 10;
+ int slidery = 0;
+
+ (*(getfuncptr)d->dp)(-1, &itemCount);
+
+ w = d->w - gui_skin.listbox.bg.grid[0]->w - gui_skin.listbox.bg.grid[2]->w;
+ h = d->h - gui_skin.listbox.bg.grid[1]->h - gui_skin.listbox.bg.grid[7]->h;
+ lastItem = MIN(itemCount-1, firstItem + h / alfont_text_height(gui_font));
+
+
+
+ if (msg == MSG_DRAW) {
+ if (ignoreRedraw) {
+ return D_O_K;
+ }
+ rectfill(gui_bitmap, d->x, d->y, d->x + d->w, d->y+d->h, d->bg);
+ drawSkinnedRect(gui_bitmap, &gui_skin.listbox.bg, d->x, d->y, d->w, d->h);
+
+ (*(getfuncptr)d->dp)(-1, &itemCount);
+ vscroll = (h/th) < (itemCount-1);
+ if (vscroll) {
+ w = d->w - 17 - gui_skin.listbox.bg.grid[0]->w;
+ drawSkinnedRect(gui_bitmap, &gui_skin.listbox.bg, d->x+d->w-15, d->y+1, 14, d->h-2);
+ sliderh = MAX(((d->h-2)* (h / th)) / itemCount, gui_skin.listbox.bg.grid[0]->h*2);
+ slidery = ((d->h-2-sliderh) * firstItem) / (itemCount);
+ slidery+= d->y+1;
+ drawSkinnedRect(gui_bitmap, &gui_skin.listbox.vscroll, d->x+d->w-13, slidery, 11, sliderh);
+ }
+
+ rtm = alfont_text_mode(-1);
+ if (gui_bitmap->clip) {
+ cl = gui_bitmap->cl;
+ ct = gui_bitmap->ct;
+ cr = gui_bitmap->cr;
+ cb = gui_bitmap->cb;
+ } else {
+ cl=ct=0;
+ cr=gui_bitmap->w;
+ cb=gui_bitmap->h;
+ }
+ x = d->x + gui_skin.listbox.bg.grid[0]->w;
+ y = d->y + gui_skin.listbox.bg.grid[0]->h;
+ set_clip_rect(gui_bitmap, x,y, x+w, y+h);
+
+
+ if (d->flags & D_DISABLED) {
+ col = gui_skin.listbox.textcolor[3];
+ for (a=firstItem; a < lastItem; a++) {
+ alfont_textout_aa(gui_bitmap, gui_font, (*(getfuncptr)d->dp)(a, 0), x, y, col);
+ y += alfont_text_height(gui_font);
+ }
+ } else {
+ for (a=firstItem; a <= lastItem; a++) {
+ if (a==d->d1) {
+ col = gui_skin.listbox.textcolor[1];
+ rectfill(gui_bitmap, x, y, x+w, y+alfont_text_height(gui_font)-1, gui_skin.listbox.textcolor[2]);
+ } else {
+ col = gui_skin.listbox.textcolor[0];
+ }
+ alfont_textout_aa(gui_bitmap, gui_font, (*(getfuncptr)d->dp)(a, 0), x, y, col);
+ y += alfont_text_height(gui_font);
+ }
+ }
+
+ alfont_text_mode(rtm);
+ set_clip_rect(gui_bitmap, cl, ct, cr, cb);
+
+ } else if (msg == MSG_CLICK) {
+
+ x = d->x + gui_skin.listbox.bg.grid[0]->w;
+ y = d->y + gui_skin.listbox.bg.grid[0]->h;
+
+ sliderh = MAX(((d->h-2)* (h / th)) / itemCount, gui_skin.listbox.bg.grid[0]->h*2);
+ //sliderh = ((d->h-2)* (h / th)) / itemCount;
+ slidery = ((d->h-2-sliderh) * firstItem) / (itemCount);
+ slidery+= d->y+1;
+
+ if (mouse_x > (d->x + d->w - 14) && mouse_x < (d->x+d->w-1)) {
+ // Ok, scroll bar
+ if (mouse_y >= slidery && mouse_y < slidery + sliderh) {
+ delta= mouse_y - slidery;
+ while (mouse_b) {
+ a = mouse_y - delta - d->y -1;
+ a *= itemCount;
+ a /= (d->h-2);
+ a = MID(0, a, itemCount- h/th);
+
+ if (a != d->d2) {
+ d->d2 = a;
+ scare_mouse();
+ object_message(d, MSG_DRAW, 0);
+ unscare_mouse();
+ }
+
+ slidery = ((d->h-2) * firstItem) / (itemCount);
+ slidery+= d->y+1;
+ }
+ } else if (mouse_y < slidery) {
+ a = d->d2 - (h/th)+1;
+ a = MID(0, a, itemCount- h/th);
+
+
+ d->d2 = a;
+ scare_mouse();
+ object_message(d, MSG_DRAW, 0);
+ unscare_mouse();
+
+ while (mouse_b) {
+ }
+ } else if (mouse_y > slidery + sliderh) {
+ a = d->d2 + (h/th)-1;
+ a = MID(0, a, itemCount- h/th);
+ d->d2 = a;
+
+ scare_mouse();
+ object_message(d, MSG_DRAW, 0);
+ unscare_mouse();
+
+ while (mouse_b) {
+ }
+ }
+ } else if (mouse_x >= x && mouse_x < x+w && mouse_y >= y && mouse_y < y+h) {
+
+ while (mouse_b) {
+ a = firstItem + (mouse_y-y) / alfont_text_height(gui_font);
+
+ if (a <= lastItem && a != selectedItem) {
+ d->d1 = selectedItem = a;
+ scare_mouse();
+ object_message(d, MSG_DRAW, 0);
+ unscare_mouse();
+ }
+ }
+ }
+ } else {
+ ignoreRedraw = (msg == MSG_GOTFOCUS || msg == MSG_LOSTFOCUS);
+ a = d_list_proc(msg, d, c);
+
+ if (a == D_USED_CHAR) {
+ if (d->d1 < d->d2) {
+ if (d->d1 > 0) {
+ d->d1 = d->d2;
+ }
+ } else if (d->d1 > d->d2 + h/th -1) {
+ d->d2 = d->d1 - h/th + 1;
+ }
+ }
+
+ return a;
+ }
+ return D_O_K;
+}
+
+int tmw_dialog_proc(int msg, DIALOG *d, int c) {
+ int rtm;
+ int x, y;
+
+ if (msg == MSG_CLICK) {
+ if(mouse_y < d->y + gui_skin.dialog.bg.grid[1]->h) {
+ //drag = true;
+ d->d1 = mouse_x - d->x;
+ d->d2 = mouse_y - d->y;
+ }
+ } else if (msg == MSG_DRAW) {
+ if((mouse_b & 1)&&(d->d1>=0)&&(d->d2>=0)) {//(drag==true)) {
+ x = mouse_x-d->d1;
+ y = mouse_y-d->d2;
+ if(x<15) {
+ x=0;
+ position_mouse(d->d1, mouse_y);
+ }
+ if(y<15) {
+ y=0;
+ position_mouse(mouse_x, d->d2);
+ }
+ if(x+d->w>=785) {
+ x=800-d->w;
+ position_mouse(x+d->d1, mouse_y);
+ }
+ if(y+d->h>=585) {
+ y=600-d->h;
+ position_mouse(mouse_x, y+d->d2);
+ }
+ position_dialog(active_dialog, x, y);
+ } else {
+ //drag = false;
+ d->d1 = -1;
+ d->d2 = -1;
+ }
+ drawSkinnedRect(gui_bitmap, &gui_skin.dialog.bg, d->x, d->y, d->w, d->h);
+ rtm = alfont_text_mode(-1);
+ alfont_textprintf_centre_aa(gui_bitmap, gui_font,
+ d->x + d->w/2,
+ d->y + (gui_skin.dialog.bg.grid[1]->h - alfont_text_height(gui_font))/2, d->fg, "%s", d->dp);
+ alfont_text_mode(rtm);
+ }
+ return D_O_K;
+}
+
+int reroute_slider_proc(void *dp3, int d2) {
+ int ret = 0;
+
+ if (gui__external_slider_callback != NULL) {
+ ret = gui__external_slider_callback(dp3, d2);
+ }
+ return ret;
+}
+
+// Helper function to draw a scrollable bar
+void _gui_draw_scrollable_frame(DIALOG *d, int listsize, int offset, int height, int fg_color, int bg) {
+ int i, len;
+ int xx, yy;
+
+ /* create and draw the scrollbar */
+ i = ((d->h-5) * height + listsize/2) / listsize;
+ xx = d->x+d->w-10;
+ yy = d->y;
+
+ if (offset > 0) {
+ len = (((d->h-5) * offset) + listsize/2) / listsize;
+ } else len = 0;
+ if (yy+i < d->y+d->h-3) {
+ drawSkinnedRect(gui_bitmap, &gui_skin.listbox.vscroll, xx, yy+len, 10, i);
+ } else {
+ drawSkinnedRect(gui_bitmap, &gui_skin.listbox.vscroll, xx, yy, 10, d->h-3);
+ }
+}
+
+/* _gui_draw_textbox:
+ * Helper function to draw a textbox object.
+ */
+void _gui_draw_textbox(char *thetext, int *listsize, int draw, int offset,
+ int wword, int tabsize, int x, int y, int w, int h,
+ int disabled, int fore, int deselect, int disable)
+{
+ int fg = fore;
+ int y1 = y+4;
+ int x1;
+ int len;
+ int ww = w-6;
+ char s[16];
+ char text[16];
+ char space[16];
+ char *printed = text;
+ char *scanned = text;
+ char *oldscan = text;
+ char *ignore = NULL;
+ char *tmp, *ptmp;
+ int width;
+ int line = 0;
+ int i = 0;
+ int noignore;
+ int rtm;
+
+ usetc(s+usetc(s, '.'), 0);
+ usetc(text+usetc(text, ' '), 0);
+ usetc(space+usetc(space, ' '), 0);
+
+ /* find the correct text */
+ if (thetext != NULL) {
+ printed = thetext;
+ scanned = thetext;
+ }
+
+ /* choose the text color */
+ if (disabled)
+ fg = disable;
+
+ rtm = alfont_text_mode(-1);
+
+ /* loop over the entire string */
+ while (1) {
+ width = 0;
+
+ /* find the next break */
+ while (ugetc(scanned)) {
+ /* check for a forced break */
+ if (ugetc(scanned) == '\n') {
+ scanned += uwidth(scanned);
+
+ /* we are done parsing the line end */
+ break;
+ }
+
+ /* the next character length */
+ usetc(s+usetc(s, ugetc(scanned)), 0);
+ len = alfont_text_length(gui_font, s);
+
+ /* modify length if its a tab */
+ if (ugetc(s) == '\t')
+ len = tabsize * alfont_text_length(gui_font, space);
+
+ /* check for the end of a line by excess width of next char */
+ if (width+len >= ww) {
+ /* we have reached end of line do we go back to find start */
+ if (wword) {
+ /* remember where we were */
+ oldscan = scanned;
+ noignore = FALSE;
+
+ /* go backwards looking for start of word */
+ while (!uisspace(ugetc(scanned))) {
+ /* don't wrap too far */
+ if (scanned == printed) {
+ /* the whole line is filled, so stop here */
+ tmp = ptmp = scanned;
+ while (ptmp != oldscan) {
+ ptmp = tmp;
+ tmp += uwidth(tmp);
+ }
+ scanned = ptmp;
+ noignore = TRUE;
+ break;
+ }
+ /* look further backwards to wrap */
+ tmp = ptmp = printed;
+ while (tmp < scanned) {
+ ptmp = tmp;
+ tmp += uwidth(tmp);
+ }
+ scanned = ptmp;
+ }
+ /* put the space at the end of the line */
+ if (!noignore) {
+ ignore = scanned;
+ scanned += uwidth(scanned);
+ }
+ else
+ ignore = NULL;
+
+ /* check for endline at the convenient place */
+ if (ugetc(scanned) == '\n')
+ scanned += uwidth(scanned);
+ }
+ /* we are done parsing the line end */
+ break;
+ }
+
+ /* the character can be added */
+ scanned += uwidth(scanned);
+ width += len;
+ }
+
+ /* check if we are to print it */
+ if ((draw) && (line >= offset) && (y1+text_height(font) < (y+h-3))) {
+ x1 = x+4;
+
+ /* the initial blank bit */
+ //rectfill(gui_bitmap, x+2, y1, x1-1, y1+text_height(font), deselect);
+
+ /* print up to the marked character */
+ while (printed != scanned) {
+ /* do special stuff for each charater */
+ switch (ugetc(printed)) {
+
+ case '\r':
+ case '\n':
+ /* don't print endlines in the text */
+ break;
+
+ /* possibly expand the tabs */
+ case '\t':
+ for (i=0; i<tabsize; i++) {
+ usetc(s+usetc(s, ' '), 0);
+ alfont_textout_aa(gui_bitmap, gui_font, s, x1, y1, fg);
+ x1 += alfont_text_length(gui_font, s);
+ }
+ break;
+
+ /* print a normal character */
+ default:
+ if (printed != ignore) {
+ usetc(s+usetc(s, ugetc(printed)), 0);
+ alfont_textout_aa(gui_bitmap, gui_font, s, x1, y1, fg);
+ x1 += alfont_text_length(gui_font, s);
+ }
+ }
+
+ /* goto the next character */
+ printed += uwidth(printed);
+ }
+ /* the last blank bit */
+ /*if (x1 <= x+w-3)
+ rectfill(gui_bitmap, x1, y1, x+w-3, y1+alfont_text_height(gui_font)-1, deselect);*/
+
+ /* print the line end */
+ y1 += alfont_text_height(gui_font);
+ }
+ printed = scanned;
+
+ /* we have done a line */
+ line++;
+
+ /* check if we are at the end of the string */
+ if (!ugetc(printed)) {
+ /* the under blank bit */
+ /*if (draw)
+ rectfill(gui_bitmap, x+1, y1, x+w-3, y+h-1, deselect);*/
+
+ /* tell how many lines we found */
+ *listsize = line;
+ alfont_text_mode(rtm);
+ return;
+ }
+ }
+
+ alfont_text_mode(rtm);
+}
+
+int tmw_textbox_proc(int msg, DIALOG *d, int c) {
+ int height, bar, ret = D_O_K;
+ int start, top, bottom, l;
+ int used, delta;
+ int fg_color = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
+
+ /* calculate the actual height */
+ height = (d->h-8) / alfont_text_height(gui_font);
+
+ switch (msg) {
+
+ case MSG_START:
+ /* measure how many lines of text we contain */
+ _gui_draw_textbox((char *)d->dp, &d->d1,
+ 0, /* DONT DRAW anything */
+ d->d2, !(d->flags & D_SELECTED), 8,
+ d->x, d->y, d->w, d->h,
+ (d->flags & D_DISABLED),
+ 0, 0, 0);
+ break;
+
+ case MSG_DRAW:
+ /* tell the object to sort of draw, but only calculate the listsize */
+ _gui_draw_textbox((char *)d->dp, &d->d1,
+ 0, /* DONT DRAW anything */
+ d->d2, !(d->flags & D_SELECTED), 8,
+ d->x, d->y, d->w, d->h,
+ (d->flags & D_DISABLED),
+ 0, 0, 0);
+
+ if (d->d1 > height) {
+ bar = 12;
+ }
+ else {
+ bar = 0;
+ d->d2 = 0;
+ }
+
+ /* now do the actual drawing */
+ _gui_draw_textbox((char *)d->dp, &d->d1, 1, d->d2,
+ !(d->flags & D_SELECTED), 8,
+ d->x, d->y, d->w-bar, d->h,
+ (d->flags & D_DISABLED),
+ fg_color, d->bg, gui_mg_color);
+
+ /* draw the frame around */
+ _gui_draw_scrollable_frame(d, d->d1, d->d2, height, fg_color, d->bg);
+
+ break;
+
+ case MSG_CLICK:
+ /* figure out if it's on the text or the scrollbar */
+ bar = (d->d1 > height);
+
+ if ((!bar) || (gui_mouse_x() < d->x+d->w-13)) {
+ /* clicked on the text area */
+ ret = D_O_K;
+ }
+ else {
+ /* clicked on the scroll area */
+ _handle_scrollable_scroll_click(d, d->d1, &d->d2, height);
+ }
+ break;
+
+ case MSG_CHAR:
+ start = d->d2;
+ used = D_USED_CHAR;
+
+ if (d->d1 > 0) {
+ if (d->d2 > 0)
+ top = d->d2+1;
+ else
+ top = 0;
+
+ l = (d->h-8)/alfont_text_height(gui_font);
+
+ bottom = d->d2 + l - 1;
+ if (bottom >= d->d1-1)
+ bottom = d->d1-1;
+ else
+ bottom--;
+
+ if ((c>>8) == KEY_UP)
+ d->d2--;
+ else if ((c>>8) == KEY_DOWN)
+ d->d2++;
+ else if ((c>>8) == KEY_HOME)
+ d->d2 = 0;
+ else if ((c>>8) == KEY_END)
+ d->d2 = d->d1-l;
+ else if ((c>>8) == KEY_PGUP)
+ d->d2 -= (bottom-top) ? bottom-top : 1;
+ else if ((c>>8) == KEY_PGDN)
+ d->d2 += (bottom-top) ? bottom-top : 1;
+ else
+ used = D_O_K;
+
+ /* make sure that the list stays in bounds */
+ if (d->d2 > d->d1-l)
+ d->d2 = d->d1-l;
+ if (d->d2 < 0)
+ d->d2 = 0;
+ }
+ else
+ used = D_O_K;
+
+ /* if we changed something, better redraw... */
+ if (d->d2 != start)
+ d->flags |= D_DIRTY;
+
+ ret = used;
+ break;
+
+ case MSG_WHEEL:
+ l = (d->h-8)/alfont_text_height(gui_font);
+ delta = (l > 3) ? 3 : 1;
+
+ /* scroll, making sure that the list stays in bounds */
+ start = d->d2;
+ d->d2 = (c > 0) ? MAX(0, d->d2-delta) : MIN(d->d1-l, d->d2+delta);
+
+ /* if we changed something, better redraw... */
+ if (d->d2 != start)
+ d->flags |= D_DIRTY;
+
+ ret = D_O_K;
+ break;
+
+ case MSG_WANTFOCUS:
+ /* if we don't have a scrollbar we can't do anything with the focus */
+ if (d->d1 > height)
+ ret = D_WANTFOCUS;
+ break;
+
+ default:
+ ret = D_O_K;
+ }
+
+ return ret;
+}
+
+int tmw_bitmap_proc(int msg, DIALOG *d, int c) {
+ if(msg==MSG_DRAW) {
+ drawSkinnedRect(gui_bitmap, &gui_skin.textbox.bg, d->x, d->y, d->w, d->h);
+ if(d->dp!=NULL)
+ masked_blit(((BITMAP *)d->dp), gui_bitmap, 0, 0, d->x+(d->w-d->d1)/2, d->y+2, d->d1, d->d2);
+ }
+ return D_O_K;
+}
+
+void ok(const char *title, const char *message) {
+DIALOG alert_dialog[] = {
+ /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
+ { tmw_dialog_proc, 0, 0, 0, 60, 0, -1, 0, 0, 0, 0, (void *)title, NULL, NULL },
+ { tmw_text_proc, 2, 22, 0, 0, 0, 0, 0, 0, 0, 0, (void *)message, NULL, NULL },
+ { tmw_button_proc, 0, 40, 44, 18, 0, -1, 'o', D_EXIT, -1, 0, (char *)"&Ok", NULL, NULL },
+ { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }};
+
+ BITMAP *temp = gui_bitmap;
+ gui_bitmap = screen;
+ show_mouse(screen);
+ alert_dialog[0].w = alfont_text_length(gui_font, message)+4;
+ alert_dialog[1].w = alfont_text_length(gui_font, message);
+ alert_dialog[1].h = alfont_text_height(gui_font);
+ alert_dialog[2].x = alfont_text_length(gui_font, message)/2-22;
+ position_dialog(alert_dialog, 400-alert_dialog[0].w/2, 270);
+ do_dialog(alert_dialog, 2);
+ show_mouse(NULL);
+ gui_bitmap = temp;
+}
+
+unsigned int yes_no(const char *title, const char *message) {
+ unsigned int ret;
+ DIALOG alert_dialog[] = {
+ /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
+ { tmw_dialog_proc, 0, 0, 0, 60, 0, -1, 0, 0, 0, 0, (void *)title, NULL, NULL },
+ { tmw_text_proc, 2, 22, 0, 0, 0, 0, 0, 0, 0, 0, (void *)message, NULL, NULL },
+ { tmw_button_proc, 0, 40, 44, 18, 0, -1, 'o', D_EXIT, -1, 0, (char *)"&Yes", NULL, NULL },
+ { tmw_button_proc, 0, 40, 44, 18, 0, -1, 'o', D_EXIT, -1, 0, (char *)"&No", NULL, NULL },
+ { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }};
+
+ BITMAP *temp = gui_bitmap;
+ gui_bitmap = screen;
+ show_mouse(screen);
+ int width = alfont_text_length(gui_font, message)+4;
+ if(width<100)width=100;
+ alert_dialog[0].w = width;
+ alert_dialog[1].w = alfont_text_length(gui_font, message);
+ alert_dialog[1].h = alfont_text_height(gui_font);
+ alert_dialog[2].x = width/2-46;
+ alert_dialog[2].x = width/2+2;
+ position_dialog(alert_dialog, 400-width/2, 270);
+ ret = do_dialog(alert_dialog, 3);
+ show_mouse(NULL);
+ gui_bitmap = temp;
+ return ret-2;
+}
diff --git a/src/gui/gui.h b/src/gui/gui.h
new file mode 100644
index 00000000..36973b65
--- /dev/null
+++ b/src/gui/gui.h
@@ -0,0 +1,121 @@
+/**
+
+ 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
+
+*/
+
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#ifndef _TMW_GUI
+#define _TMW_GUI
+
+#include <allegro.h>
+#include <alfont.h>
+#include <string.h>
+
+typedef struct {
+ BITMAP *grid[9];
+} LexSkinnedRect;
+
+typedef struct {
+ LexSkinnedRect background[4];
+ int textcolor[4];
+} LexButton;
+
+typedef struct {
+ BITMAP *hSlider[3];
+ BITMAP *vSlider[3];
+ BITMAP *hGrip;
+ BITMAP *vGrip;
+} LexSlider;
+
+typedef struct {
+ BITMAP *normal;
+ BITMAP *checked;
+ BITMAP *disabled;
+ BITMAP *disabled_checked;
+ int textcolor[2];
+} LexCheckbox;
+
+typedef struct {
+ BITMAP *normal;
+ BITMAP *checked;
+ BITMAP *disabled;
+ BITMAP *disabled_checked;
+ int textcolor[2];
+} LexRadiobutton;
+
+typedef struct {
+ LexSkinnedRect bg;
+ int textcolor[2];
+} LexTextbox;
+
+typedef struct {
+ LexSkinnedRect bg;
+ LexSkinnedRect vscroll;
+ int textcolor[4];
+} LexListbox;
+
+typedef struct {
+ LexSkinnedRect bg;
+} LexDialog;
+
+typedef struct {
+ LexButton button;
+ LexSlider slider;
+ LexCheckbox checkbox;
+ LexRadiobutton radiobutton;
+ LexTextbox textbox;
+ LexListbox listbox;
+ LexDialog dialog;
+} LexSkin;
+
+extern LexSkin gui_skin;
+extern BITMAP *gui_bitmap;
+extern ALFONT_FONT *gui_font;
+
+/* Definition of the callback function prototypes */
+typedef int (*gui_buttonCallback)(int id);
+typedef char *(*getfuncptr)(int, int *);
+
+void init_gui(BITMAP *dest_bitmap, const char *skin);
+void gui_exit();
+int gui_update(DIALOG_PLAYER *player);
+int gui_load_skin(const char* skinname);
+void gui_shutdown(void);
+
+int tmw_button_proc(int msg, DIALOG *d, int c);
+int tmw_slider_proc(int msg, DIALOG *d, int c);
+int tmw_check_proc(int msg, DIALOG *d, int c);
+int tmw_radio_proc(int msg, DIALOG *d, int c);
+int tmw_edit_proc(int msg, DIALOG *d, int c);
+int tmw_password_proc(int msg, DIALOG *d, int c);
+int tmw_list_proc(int msg, DIALOG *d, int c);
+int tmw_text_proc(int msg, DIALOG *d, int c);
+int tmw_dialog_proc(int msg, DIALOG *d, int c);
+int tmw_textbox_proc(int msg, DIALOG *d, int c);
+int tmw_bitmap_proc(int msg, DIALOG *d, int c);
+
+void ok(const char *title, const char *message);
+unsigned int yes_no(const char *title, const char *message);
+
+#endif
diff --git a/src/gui/inventory.cpp b/src/gui/inventory.cpp
new file mode 100644
index 00000000..72c2cbaa
--- /dev/null
+++ b/src/gui/inventory.cpp
@@ -0,0 +1,249 @@
+/**
+
+ 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
+
+*/
+
+#include "inventory.h"
+
+void TmwInventory::create(int tempxpos, int tempypos) {
+ xpos =tempxpos;
+ ypos =tempypos;
+
+ itemPIC[0].pic = load_bitmap("items/herb.bmp", NULL); //ID=0
+ itemPIC[1].pic = load_bitmap("items/magicthing.bmp", NULL); //ID=1
+ empty = load_bitmap("items/empty.bmp", NULL);
+ selected = load_bitmap("items/selected.bmp", NULL);
+
+ for(int i = 0; i< 10; i++) {
+ for(int ii = 0; ii< 10; ii++) {
+ items[i][ii].flag = 0; //doesn't hold anything
+ items[i][ii].itemIDNum = -1; //doesn't exist :)
+ items[i][ii].xpos = empty->w*i+1;
+ items[i][ii].ypos = empty->h*ii;
+ items[i][ii].num = 0;
+ }
+ }
+
+ //create two fake items
+ items[0][0].flag = 1;
+ items[0][0].itemIDNum = 0;
+ items[0][0].num = 1;
+
+ items[2][0].flag = 1;
+ items[2][0].itemIDNum = 1;
+ items[2][0].num = 3;
+
+ backgroundSmall = create_bitmap(empty->w*10+10, empty->h+10);
+ backgroundBig = create_bitmap(empty->w*10+10, empty->h*10+10);
+ title = create_bitmap(15, backgroundSmall->h);
+ floodfill(title,0,0,200);
+ floodfill(backgroundSmall,0,0,100);
+ floodfill(backgroundBig,0,0,100);
+ areDisplaying = 0;
+ dragingWindow = 0;
+ lastSelectedX = -1;
+ lastSelectedY = -1;
+ bigwindow = 0; //false
+}
+
+void TmwInventory::draw(BITMAP * buffer) {
+ // let's draw the inventory
+ if(areDisplaying) {
+ int max;
+ if(!bigwindow) {
+ max = 1;
+ blit(backgroundSmall, buffer, 0, 0, xpos-5, ypos-5, 800, 600);
+ } else {
+ max = 10;
+ blit(backgroundBig, buffer, 0, 0, xpos-5, ypos-5, 800, 600);
+ }
+ blit(title, buffer, 0, 0, xpos+backgroundSmall->w-5, ypos+-5, 800, 600);
+ for(int itemX = 0; itemX< 10; itemX++) {
+ for(int itemY = 0;itemY<max;itemY++) {
+ int draw = 0;
+
+ blit(empty, buffer, 0, 0, (xpos+items[itemX][itemY].xpos), (ypos+items[itemX][itemY].ypos), 800, 600);
+
+ if(mouse_b&1) {
+ if(xpos+items[itemX][itemY].xpos+empty->w > mouse_x && xpos+items[itemX][itemY].xpos < mouse_x)
+ if(ypos+items[itemX][itemY].ypos+empty->h > mouse_y && ypos+items[itemX][itemY].ypos < mouse_y) {
+ //selected
+ masked_blit(selected, buffer, 0, 0, (xpos+items[itemX][itemY].xpos), (ypos+items[itemX][itemY].ypos), 800, 600);
+ draw = 1;
+ if(items[itemX][itemY].flag) // have a item
+ if(!dragingItem) { //not dragging it
+ dragingItem=1; //begin to drag
+ ghostOldIDX = itemX;
+ ghostOldIDY = itemY;
+ ghostID = items[itemX][itemY].itemIDNum;
+ ghostX = mouse_x;
+ ghostY = mouse_y;
+ }
+ }
+ } else {
+ if(lastSelectedX != -1 && dragingItem) { // have stoped dragging it over a itemholder
+ //swap place
+ itemHolder temp;
+ int txpos1,typos1,txpos2,typos2;
+ txpos1 = items[lastSelectedX][lastSelectedY].xpos;
+ typos1 = items[lastSelectedX][lastSelectedY].ypos;
+ txpos2 = items[ghostOldIDX][ghostOldIDY].xpos;
+ typos2 = items[ghostOldIDX][ghostOldIDY].ypos;
+ temp = items[lastSelectedX][lastSelectedY];
+ items[lastSelectedX][lastSelectedY] = items[ghostOldIDX][ghostOldIDY];
+ items[ghostOldIDX][ghostOldIDY] = temp;
+ items[lastSelectedX][lastSelectedY].xpos = txpos1;
+ items[lastSelectedX][lastSelectedY].ypos = typos1;
+ items[ghostOldIDX][ghostOldIDY].xpos = txpos2;
+ items[ghostOldIDX][ghostOldIDY].ypos = typos2;
+ }
+ dragingItem = 0; // stop dragging
+ }
+
+ if(xpos+items[itemX][itemY].xpos+empty->w > mouse_x && xpos+items[itemX][itemY].xpos < mouse_x && ypos+items[itemX][itemY].ypos+empty->h > mouse_y && ypos+items[itemX][itemY].ypos < mouse_y ) {
+ // a hoover
+ lastSelectedX = itemX;
+ lastSelectedY = itemY;
+ }
+
+ if(items[itemX][itemY].flag) //draw the item
+ masked_blit(itemPIC[items[itemX][itemY].itemIDNum].pic, buffer, 0, 0, (xpos+items[itemX][itemY].xpos), (ypos+items[itemX][itemY].ypos), 800, 600);
+
+ //the number of that item
+ if(!bigwindow)
+ alfont_textprintf_aa(buffer, gui_font, xpos+items[itemX][itemY].xpos+20, ypos+items[itemX][itemY].ypos+empty->h-15, makecol(0,0,0), "%i",items[itemX][itemY].num);
+ else
+ alfont_textprintf_aa(buffer, gui_font, xpos+items[itemX][itemY].xpos+20, ypos+items[itemX][itemY].ypos+empty->h-15, makecol(0,0,0), "%i",items[itemX][itemY].num);
+ }
+ }
+
+
+ if(mouse_b&2) {
+ if(xpos+title->w+backgroundSmall->w > mouse_x && xpos+backgroundSmall->w < mouse_x)
+ if(ypos+title->h > mouse_y && ypos < mouse_y) {
+ if(bigwindow)
+ bigwindow=0;
+ else
+ bigwindow = 1;
+ }
+ }
+ }
+
+ if(mouse_b&1) {
+ if(xpos+title->w+backgroundSmall->w > mouse_x && xpos+backgroundSmall->w < mouse_x)
+ if(ypos+title->h > mouse_y && ypos < mouse_y) { //begin to move the window
+ xpos = mouse_x-(backgroundSmall->w);
+ ypos = mouse_y;
+ dragingWindow=1;
+ }
+ } else { dragingWindow=0;}
+
+ if(dragingWindow) { //moving the window ?
+ xpos = mouse_x-(backgroundSmall->w);
+ ypos = mouse_y;
+ }
+
+ if(dragingItem) { //moving the item
+ masked_blit(itemPIC[ghostID].pic, buffer, 0, 0, ghostX, ghostY, 800, 600);
+ ghostX = mouse_x;
+ ghostY = mouse_y;
+ }
+}
+
+
+void TmwInventory::show(int val) {
+ if(val)
+ areDisplaying = 1;
+
+ if(!val)
+ areDisplaying = 0;
+}
+
+int TmwInventory::addItem(int idnum, int antal)
+{
+int found, tempi, tempii;
+found = 0;
+tempi = -1;
+for(int i = 0; i< 10; i++)
+ {
+ for(int ii = 0; ii< 10; ii++)
+ {
+ if(items[i][ii].itemIDNum == idnum)
+ { found = 1; items[i][ii].num = antal; return -2; }
+ }
+ }
+if(!found)
+{
+for(int ii = 0; ii< 10; ii++)
+ {
+ for(int i = 0; i< 10; i++)
+ {
+ if(items[i][ii].flag == 0)
+ {tempi = i; tempii = ii; ii=10;i=10;}
+ }
+ }
+ if(tempi != -1)
+ {
+ items[tempi][tempii].flag = 1;
+ items[tempi][tempii].itemIDNum = idnum;
+ items[tempi][tempii].num = antal;
+ return 1;
+ } else { return -1; }
+
+}
+return -3;
+}
+
+int TmwInventory::rmItem(int idnum)
+{
+int found, tempi;
+found = 0;
+tempi = -1;
+for(int i = 0; i< 10; i++)
+ {
+ for(int ii = 0; ii< 10; ii++)
+ {
+ if(items[i][ii].itemIDNum == idnum)
+ { items[i][ii].itemIDNum = -1;
+ items[i][ii].flag = 0;
+ items[i][ii].num = 0;
+ return 1;
+ }
+ }
+ }
+return -1;
+}
+
+int TmwInventory::changeNum(int idnum, int antal)
+{
+int found, tempi;
+found = 0;
+tempi = -1;
+for(int i = 0; i< 10; i++)
+ {
+ for(int ii = 0; ii< 10; ii++)
+ {
+ if(items[i][ii].itemIDNum == idnum)
+ { items[i][ii].num = antal; return 1; }
+ }
+ }
+return -1;
+} \ No newline at end of file
diff --git a/src/gui/inventory.h b/src/gui/inventory.h
new file mode 100644
index 00000000..75939950
--- /dev/null
+++ b/src/gui/inventory.h
@@ -0,0 +1,80 @@
+/**
+
+ 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
+
+*/
+
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#ifndef _INVENTORY_H
+#define _INVENTORY_H
+#include <allegro.h>
+#ifdef WIN32
+#include <winalleg.h>
+#endif
+#include "../main.h"
+#include "../game.h"
+#include "../log.h"
+#include "../Net/network.h"
+#include "gui.h"
+
+struct itemHolder { // the holder of a item
+ int flag; // don't really know why I use this :)
+ int itemIDNum; // the id of the item
+ int num; // number of items
+ int xpos,ypos; // where am I?
+};
+
+struct itemID {//the holder of the pictures for each item, maybe more in the future
+ BITMAP * pic;
+};
+
+class TmwInventory{
+ public:
+ TmwInventory() {};
+ ~TmwInventory() {};
+
+ void create(int tempxpos, int tempypos); // create the window
+ void draw(BITMAP *); // draw the window (if areDisplaying != 0 )
+ void show(int val); // choose between the show and don't show the window
+ void toggle() { if(areDisplaying){show(0);}else{show(1);} }
+ //API
+ int addItem(int idnum, int antal); //add a item
+ int rmItem(int idnum); //remove a item
+ int changeNum(int idnum, int antal); // change nummber of a item
+ //END API
+ private:
+ BITMAP * backgroundSmall;
+ BITMAP * backgroundBig;
+ BITMAP * title;
+ BITMAP * empty;
+ BITMAP * selected;
+ itemHolder items[10][10]; // this is the test holder of items
+ itemID itemPIC[2]; // I only got two items
+ int ghostX, ghostY, ghostID, ghostOldIDX,ghostOldIDY; //info needed when moving item
+ int dragingItem, lastSelectedX,lastSelectedY; //info needed when moving item
+ int areDisplaying, dragingWindow;
+ int bigwindow;
+ int xpos, ypos; // Where am I ?
+};
+
+#endif
diff --git a/src/gui/login.cpp b/src/gui/login.cpp
new file mode 100644
index 00000000..e3cb6195
--- /dev/null
+++ b/src/gui/login.cpp
@@ -0,0 +1,139 @@
+/**
+
+ 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
+
+*/
+
+#include "login.h"
+#include "../Graphic/graphic.h"
+
+/** Display login GUI */
+void login() {
+DIALOG login_dialog[] = {
+ /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
+ { tmw_dialog_proc, 300, 252, 200, 96, 0, -1, 0, 0, 0, 0, (char*)"Login", NULL, NULL },
+ { tmw_text_proc, 304, 284, 50, 10, 0, 0, 0, 0, 0, 0, (char*)"Name:", NULL, NULL },
+ { tmw_text_proc, 304, 304, 50, 10, 0, 0, 0, 0, 0, 0,(char*)"Password:", NULL, NULL },
+ { tmw_edit_proc, 360, 280, 130, 18, 0, -1, 0, 0, 24, 0, username, NULL, NULL },
+ { tmw_password_proc, 360, 300, 130, 18, 0, -1, 0, 0, 24, 0, password, NULL, NULL },
+ { tmw_button_proc, 398, 322, 44, 18, 0, -1, 'o', D_EXIT, -1, 0, (char*)"&Ok", NULL, NULL },
+ { tmw_button_proc, 446, 322, 44, 18, 0, -1, 'c', D_EXIT, -1, 0, (char*)"&Cancel", NULL, NULL },
+ { tmw_check_proc, 304, 322, 60, 18, 0, 0, '1', 0, 0, 0, (char*)"keep", NULL, NULL },
+ { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
+};
+
+ if(get_config_int("login", "remember", 0)!=0) {
+ login_dialog[7].flags = D_SELECTED;
+ if(get_config_string("login", "username", 0))strcpy(username, get_config_string("login", "username", 0));
+ else strcpy(username, "player\0");
+ }
+ centre_dialog(login_dialog);
+ DIALOG_PLAYER *player = init_dialog(login_dialog, -1);
+ int gui_exit = 1;
+ while ((!key[KEY_ESC])&&(gui_exit)&&(state!=EXIT)&&(!key[KEY_ENTER])) {
+ clear_bitmap(buffer);
+ if(stretch_mode!=0)blit((BITMAP *)graphic[LOGIN_BMP].dat, buffer, 0, 0, 80, 60, 640, 480);
+ else blit((BITMAP *)graphic[LOGIN_BMP].dat, buffer, 0, 0, -120, -90, 640, 480);
+
+ gui_exit = gui_update(player);
+ blit(buffer, screen, 0, 0, 0, 0, 800, 600);
+ }
+ state = EXIT;
+ set_config_int("login", "remember", (login_dialog[7].flags & D_SELECTED)>>1);
+ if(login_dialog[7].flags & D_SELECTED) {
+ if(!username)strcpy(username, "player\0");
+ set_config_string("login", "username", username);
+ } else set_config_string("login", "username", "player\0");
+ log("Player", "username", username);
+ gui_exit = shutdown_dialog(player);
+ if((gui_exit==5)||(key[KEY_ENTER])) {
+ if(username[0]=='\0') {
+ ok("Error", "Enter your username first");
+ warning("Enter your username first");
+ state = LOGIN;
+ } else {
+ server_login();
+ close_session();
+ }
+ }
+}
+
+/** Attempt to login to login server */
+void server_login() {
+ int ret;
+
+ // Connect to login server
+ ret = open_session(get_config_string("server", "host", 0), get_config_int("server", "port", 0));
+ if(ret==SOCKET_ERROR) {
+ state = LOGIN;
+ ok("Error", "Unable to connect to login server");
+ warning("Unable to connect to login server");
+ return;
+ }
+
+ // Send login infos
+
+
+ WFIFOW(0) = net_w_value(0x0064);
+
+ WFIFOL(2) = 0;
+ memcpy(WFIFOP(6), username, 24);
+ memcpy(WFIFOP(30), password, 24);
+ WFIFOB(54) = 0;
+ WFIFOSET(55);
+
+ while((in_size<23)||(out_size>0))flush();
+ log_hex("Login_Packet", "Packet_ID", RFIFOW(0));
+ log_int("Login_Packet", "Packet_length", get_packet_length(RFIFOW(0)));
+
+ if(RFIFOW(0)==0x0069) {
+ while(in_size<RFIFOW(2))flush();
+ n_server = (RFIFOW(2)-47)/32;
+ server_info = (SERVER_INFO *)malloc(sizeof(SERVER_INFO)*n_server);
+ account_ID = RFIFOL(8);
+ session_ID1 = RFIFOL(4);
+ session_ID2 = RFIFOL(12);
+ sex = RFIFOB(46);
+ for(int i=0;i<n_server;i++) {
+ server_info[i].address = RFIFOL(47+32*i);
+ memcpy(server_info[i].name, RFIFOP(47+32*i+6), 20);
+ server_info[i].online_users = RFIFOW(47+32*i+26);
+ server_info[i].port = RFIFOW(47+32*i+4);
+ state = CHAR_SERVER;
+ }
+ log("Login_Packet", "server_address", iptostring(server_info[0].address));
+ log("Login_Packet", "server_name", server_info[0].name);
+ log_int("Login_Packet", "server_users", server_info[0].online_users);
+ log_int("Login_Packet", "server_port", server_info[0].port);
+ RFIFOSKIP(RFIFOW(2));
+ } else if(RFIFOW(0)==0x006a) {
+ switch(RFIFOB(2)) {
+ case 0:
+ ok("Error", "Unregistered ID");
+ break;
+ case 1:
+ ok("Error", "Wrong password");
+ break;
+ }
+ state = LOGIN;
+ RFIFOSKIP(23);
+ } else ok("Error", "Unknown error");
+ // Todo: add other packets, also encrypted
+}
diff --git a/src/gui/login.h b/src/gui/login.h
new file mode 100644
index 00000000..c181e0eb
--- /dev/null
+++ b/src/gui/login.h
@@ -0,0 +1,43 @@
+/**
+
+ 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
+
+*/
+
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#ifndef _LOGIN_H
+#define _LOGIN_H
+
+#include <allegro.h>
+#ifdef WIN32
+#include <winalleg.h>
+#endif
+#include "../main.h"
+#include "../log.h"
+#include "../Net/network.h"
+#include "gui.h"
+
+void login();
+void server_login();
+
+#endif
diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp
new file mode 100644
index 00000000..f1ccdcc2
--- /dev/null
+++ b/src/gui/skill.cpp
@@ -0,0 +1,56 @@
+/**
+
+ 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
+
+ By ElvenProgrammer aka Eugenio Favalli (umperio@users.sourceforge.net)
+
+*/
+
+#include "skill.h"
+
+extern CHAR_SEL_INFO *char_info;
+
+char str_string[8];
+char agi_string[8];
+char vit_string[8];
+char int_string[8];
+char dex_string[8];
+char luk_string[8];
+
+DIALOG skill_dialog[] = {
+ /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
+ { tmw_dialog_proc, 300, 200, 120, 60, 0, 0, 0, 0, 0, 0, (char *)"Skill", NULL, NULL },
+ { tmw_text_proc, 304, 224, 252, 100, 0, 0, 0, 0, 0, 0, str_string, NULL, NULL },
+ { tmw_text_proc, 304, 234, 252, 100, 0, 0, 0, 0, 0, 0, agi_string, NULL, NULL },
+ { tmw_text_proc, 304, 244, 252, 100, 0, 0, 0, 0, 0, 0, vit_string, NULL, NULL },
+ { tmw_text_proc, 364, 224, 252, 100, 0, 0, 0, 0, 0, 0, int_string, NULL, NULL },
+ { tmw_text_proc, 364, 234, 252, 100, 0, 0, 0, 0, 0, 0, dex_string, NULL, NULL },
+ { tmw_text_proc, 364, 244, 252, 100, 0, 0, 0, 0, 0, 0, luk_string, NULL, NULL },
+ { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
+};
+
+void update_skill_dialog() {
+ sprintf(str_string, "STR: %i", char_info->STR);
+ sprintf(agi_string, "AGI: %i", char_info->AGI);
+ sprintf(vit_string, "VIT: %i", char_info->VIT);
+ sprintf(int_string, "INT: %i", char_info->INT);
+ sprintf(dex_string, "DEX: %i", char_info->DEX);
+ sprintf(luk_string, "LUK: %i", char_info->LUK);
+}
diff --git a/src/gui/skill.h b/src/gui/skill.h
new file mode 100644
index 00000000..a0ce031d
--- /dev/null
+++ b/src/gui/skill.h
@@ -0,0 +1,40 @@
+/**
+
+ 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
+
+ By ElvenProgrammer aka Eugenio Favalli (umperio@users.sourceforge.net)
+
+*/
+
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#ifndef _SKILL_H
+#define _SKILL_H
+
+#include <allegro.h>
+#include "../main.h"
+
+//DIALOG skill_dialog[];
+
+void update_skill_dialog();
+
+#endif
diff --git a/src/log.cpp b/src/log.cpp
new file mode 100644
index 00000000..785418cc
--- /dev/null
+++ b/src/log.cpp
@@ -0,0 +1,189 @@
+/**
+
+ 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
+
+*/
+
+#include "log.h"
+
+int warning_n; // Keep warning number
+
+#define LOG_FILE "The Mana World.log"
+#define LOG_VERSION "0.3"
+
+void init_log() {
+#ifdef WIN32
+ remove(LOG_FILE);
+#else
+ unlink(LOG_FILE);
+#endif
+
+ push_config_state();
+ set_config_file(LOG_FILE);
+#ifdef WIN32 // for the moment i cant find a valuable unix function for _strdate // Sull
+ char date[9];
+ set_config_string("Core", "date", _strdate(date));
+#endif
+ set_config_string("Core", "log_version", LOG_VERSION);
+ set_config_string("Core", "Allegro_ID", allegro_id);
+ switch(os_type) {
+ case OSTYPE_UNKNOWN:
+ set_config_string("Core", "Os", "unknown, or regular MSDOS");
+ break;
+ case OSTYPE_WIN3:
+ set_config_string("Core", "Os", "Windows 3.1 or earlier");
+ break;
+ case OSTYPE_WIN95:
+ set_config_string("Core", "Os", "Windows 95");
+ break;
+ case OSTYPE_WIN98:
+ set_config_string("Core", "Os", "Windows 98");
+ break;
+ case OSTYPE_WINME:
+ set_config_string("Core", "Os", "Windows ME");
+ break;
+ case OSTYPE_WINNT:
+ set_config_string("Core", "Os", "Windows NT");
+ break;
+ case OSTYPE_WIN2000:
+ set_config_string("Core", "Os", "Windows 2000");
+ break;
+ case OSTYPE_WINXP:
+ set_config_string("Core", "Os", "Windows XP");
+ break;
+ case OSTYPE_OS2:
+ set_config_string("Core", "Os", "OS/2");
+ break;
+ case OSTYPE_WARP:
+ set_config_string("Core", "Os", "OS/2 Warp 3");
+ break;
+ case OSTYPE_DOSEMU:
+ set_config_string("Core", "Os", "Linux DOSEMU");
+ break;
+ case OSTYPE_OPENDOS:
+ set_config_string("Core", "Os", "Caldera OpenDOS");
+ break;
+ case OSTYPE_LINUX:
+ set_config_string("Core", "Os", "Linux");
+ break;
+ case OSTYPE_SUNOS:
+ set_config_string("Core", "Os", "SunOS/Solaris");
+ break;
+ case OSTYPE_FREEBSD:
+ set_config_string("Core", "Os", "FreeBSD");
+ break;
+ case OSTYPE_NETBSD:
+ set_config_string("Core", "Os", "NetBSD");
+ break;
+ case OSTYPE_IRIX:
+ set_config_string("Core", "Os", "IRIX");
+ break;
+ case OSTYPE_QNX:
+ set_config_string("Core", "Os", "QNX");
+ break;
+ case OSTYPE_UNIX:
+ set_config_string("Core", "Os", "Unknown Unix variant");
+ break;
+ case OSTYPE_BEOS:
+ set_config_string("Core", "Os", "BeOS");
+ break;
+ case OSTYPE_MACOS:
+ set_config_string("Core", "Os", "MacOS");
+ break;
+ default:
+ set_config_string("Core", "Os", "Unknown");
+ break;
+ }
+ set_config_int("Core", "Os_version", os_version);
+ set_config_int("Core", "Os_revision", os_revision);
+ if(os_multitasking)set_config_string("Core", "Multitasking", "TRUE");
+ else set_config_string("Core", "Multitasking", "FALSE");
+
+ set_config_string("Core", "CPU_Vendor", cpu_vendor);
+ switch(cpu_family) {
+ case 3:
+ set_config_string("Core", "CPU_Family", "386");
+ break;
+ case 4:
+ set_config_string("Core", "CPU_Family", "486");
+ break;
+ case 5:
+ set_config_string("Core", "CPU_Family", "Pentium");
+ break;
+ case 6:
+ set_config_string("Core", "CPU_Family", "Pentium II/III/PRO/Athlon");
+ break;
+ case 15:
+ set_config_string("Core", "CPU_Family", "Pentium IV");
+ break;
+ default:
+ set_config_string("Core", "CPU_Family", "Unknown");
+ set_config_int("Core", "CPU_Family_ID", cpu_family);
+ break;
+ }
+
+ set_config_int("Core", "CPU_model", cpu_model);
+
+ set_config_int("Core", "CPU_capabilities", cpu_capabilities);
+ pop_config_state();
+
+ warning_n = 0;
+}
+
+void log(const char *log_section, const char *log_name, const char *log_text) {
+ push_config_state();
+ set_config_file(LOG_FILE);
+ set_config_string(log_section, log_name, log_text);
+ pop_config_state();
+}
+
+void log_hex(const char *log_section, const char *log_name, const short log_value) {
+ push_config_state();
+ set_config_file(LOG_FILE);
+ set_config_hex(log_section, log_name, log_value);
+ pop_config_state();
+}
+
+void log_int(const char *log_section, const char *log_name, const int log_value) {
+ push_config_state();
+ set_config_file(LOG_FILE);
+ set_config_int(log_section, log_name, log_value);
+ pop_config_state();
+}
+
+void error(const char *error_text) {
+ log("Error", "Last_error", error_text);
+#ifdef WIN32
+ MessageBox(NULL, error_text, "Error", MB_ICONERROR|MB_OK);
+#else
+ printf("Error: %s", error_text);
+#endif
+ exit(1);
+}
+
+void warning(const char *warning_text) {
+ char warning_name[40];
+ sprintf(warning_name, "warning_%i", warning_n);
+ log("Error", warning_name, warning_text);
+}
+
+void status(const char *status_text) {
+ log("Status", "last_function", status_text);
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 00000000..5c53e5ca
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,45 @@
+/**
+
+ 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
+
+*/
+
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#ifndef _LOG_H
+#define _LOG_H
+
+#include <allegro.h>
+#ifdef WIN32
+#include <winalleg.h>
+#endif
+#include <stdio.h>
+
+void init_log();
+void log(const char *log_section, const char *log_name, const char *log_text);
+void log_hex(const char *log_section, const char *log_name, const short log_value);
+void log_int(const char *log_section, const char *log_name, const int log_value);
+void error(const char *error_text);
+void warning(const char *warning_text);
+void status(const char *status_text);
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 00000000..937c40f6
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,156 @@
+/**
+
+ 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
+
+*/
+
+#include "main.h"
+#include "./Sound/sound.h"
+#include "./Graphic/graphic.h"
+
+/* Account infos */
+int account_ID, session_ID1, session_ID2;
+char sex, n_server, n_character;
+SERVER_INFO *server_info;
+CHAR_SEL_INFO *char_info;
+
+BITMAP *playerset;
+DATAFILE *graphic, *emotions;
+
+char username[25];
+char password[25];
+int map_address, char_ID;
+short map_port;
+char map_name[16];
+unsigned char state;
+unsigned short x, y;
+unsigned char direction;
+unsigned short job, hair, hair_color;
+unsigned char stretch_mode;
+
+// new sound-engine /- kth5
+TmwSound sound;
+
+void request_exit() {
+ state = EXIT;
+}
+
+/** Do all initialization stuff */
+void init_engine() {
+ allegro_init();
+ init_log();
+ set_close_button_callback(request_exit); // we should not use set_window_close_hook() since it's deprecated and might be gone in the future /-kth5
+ set_config_file("tmw.ini");
+ #ifdef MACOSX
+ set_color_depth(32);
+ Init_SuperEagle(32);
+ #else
+ set_color_depth(16);
+ Init_SuperEagle(16);
+ #endif
+ stretch_mode = get_config_int("settings", "stretch", 0);
+ if(stretch_mode==0) {
+ if(set_gfx_mode(get_config_int("settings", "screen", 0), 400, 300, 0, 0))
+ error(allegro_error);
+ } else {
+ if(set_gfx_mode(get_config_int("settings", "screen", 0), 800, 600, 0, 0))
+ error(allegro_error);
+ }
+ if(install_keyboard())
+ error("Unable to install keyboard");
+ if(install_timer())
+ error("Unable to install timer");
+ if(install_mouse()==-1)
+ error("Unable to install mouse");
+ if(alfont_init()!=ALFONT_OK)
+ error("Unable to install AllegroFont");
+
+ buffer = create_bitmap(800, 600);
+ if(!buffer)
+ error("Not enough memory to create buffer");
+ graphic = load_datafile("./data/graphic/graphic.dat");
+ if(graphic==NULL)
+ error("Unable to load graphic datafile");
+ playerset = (BITMAP*)graphic[PLAYERSET_BMP].dat;
+ emotions = load_datafile("./data/graphic/emotions.dat");
+ if(emotions==NULL)
+ error("Unable to load emotions datafile");
+
+ init_gui(buffer, "./data/skin/aqua.skin");
+
+ state = LOGIN;
+}
+
+/** Clear the engine */
+void exit_engine() {
+ gui_exit();
+ //alfont_exit();
+ destroy_bitmap(buffer);
+ allegro_exit();
+}
+
+/** Main */
+int main() {
+ init_engine();
+
+ // initialize sound-engine and start playing intro-theme /-kth5
+ try{
+ if(get_config_int("settings", "sound", 0)==1)
+ sound.Init(32,20); // inits the sound-subsystem w/ 32 voices / 20 for mod
+ sound.SetVol(128,128,128); // sets intial volume parameters
+ //#ifdef WIN32
+ //sound.StartMIDI("Sound/Midis/city.mid",-1); // play a midi file
+ //#endif
+ }catch(const char * err){ // catch errors and show appropriate messages on-screen (elven plz... ^^)
+ ok("Sound Engine", err);
+ warning(err);
+ }
+
+ while(state!=EXIT) {
+ switch(state) {
+ case LOGIN:
+ status("LOGIN");
+ login();
+ break;
+ case CHAR_SERVER:
+ status("CHAR_SERVER");
+ char_server();
+ break;
+ case CHAR_SELECT:
+ status("CHAR_SELECT");
+ char_select();
+ break;
+ case GAME:
+ sound.StopBGM();
+ status("GAME");
+ map_start();
+ if( state==GAME )
+ game();
+ break;
+ default:
+ state = EXIT;
+ break;
+ }
+ }
+ status("EXIT");
+ exit_engine();
+ return 0;
+}
+END_OF_MAIN();
diff --git a/src/main.h b/src/main.h
new file mode 100644
index 00000000..0b4eb87a
--- /dev/null
+++ b/src/main.h
@@ -0,0 +1,86 @@
+/**
+
+ 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
+
+*/
+
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#ifndef _MAIN_H
+#define _MAIN_H
+
+#include <stdio.h>
+#include <allegro.h>
+#include <alfont.h>
+
+#include "log.h"
+#include "game.h"
+#include "./Net/protocol.h"
+#include "./Gui/login.h"
+#include "./Gui/gui.h"
+#include "./Gui/char_server.h"
+#include "./Gui/char_select.h"
+#include "./Graphic/SuperEagle.h"
+#include "./data/graphic/gfx_data.h"
+
+#define EXIT 0
+#define LOGIN 1
+#define CHAR_SERVER 2
+#define CHAR_SELECT 3
+#define CHAR_NEW 4
+#define CHAR_DEL 5
+#define GAME 6
+
+typedef struct {
+ int address;
+ short port;
+ char name[20];
+ short online_users;
+} SERVER_INFO;
+
+typedef struct {
+ int id;
+ char name[24];
+ short hp, max_hp, sp, max_sp, lv;
+ int xp, zeny, job_xp, job_lv;
+ short statp, skillp;
+ char STR, AGI, VIT, INT, DEX, LUK;
+} CHAR_SEL_INFO;
+
+extern BITMAP *playerset;
+extern DATAFILE *graphic, *emotions;
+extern char username[25];
+extern char password[25];
+extern int map_address, char_ID;
+extern short map_port;
+extern char map_name[16];
+extern int account_ID, session_ID1, session_ID2;
+extern char sex, n_server, n_character;
+extern SERVER_INFO *server_info;
+extern CHAR_SEL_INFO *char_info;
+extern unsigned char state;
+extern unsigned short x, y;
+extern unsigned char direction;
+extern unsigned short job, hair, hair_color;
+extern unsigned char stretch_mode;
+
+#endif
diff --git a/src/map.cpp b/src/map.cpp
new file mode 100644
index 00000000..c8fc3612
--- /dev/null
+++ b/src/map.cpp
@@ -0,0 +1,120 @@
+/**
+
+ 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
+
+*/
+
+#include "map.h"
+#include "log.h"
+#include "being.h"
+
+#include <stdio.h>
+#ifdef WIN32
+#include <windows.h>
+#else
+#include "./Net/win2linux.h"
+#endif
+
+MAP map;
+
+/** Loads a map file */
+bool load_map(char *map_file) {
+ PACKFILE *file = pack_fopen(map_file, "rp");
+ if(!file) {
+ warning(map_file);
+ return false;
+ }
+ pack_fread(&map, sizeof(MAP), file);
+ pack_fclose(file);
+ return true;
+}
+
+
+/** Set walkability flag for a tile */
+void set_walk(short x_c, short y_c, bool walkable) {
+ if(walkable==true)map.tiles[x_c][y_c].data[3] |= 0x0002;
+ else map.tiles[x_c][y_c].data[3] &= 0x00fd;
+}
+
+/** Tell if a tile is walkable or not */
+bool get_walk(short x_c, short y_c) {
+ bool ret = (map.tiles[x_c][y_c].data[3] & 0x0002)>0;
+ if(ret==true) {
+ NODE *node = get_head();
+ while(node && ret==true) {
+ if(get_x(node->coordinates)==x_c && get_y(node->coordinates)==y_c)
+ ret = false;
+ node = node->next;
+ }
+ return ret;
+ } else return false;
+}
+
+/** Tell if a tile is walkable or not (0=walkable,1=not walkable) */
+unsigned char get_path_walk(unsigned short x, unsigned short y) {
+ if(get_walk(x, y))return 0;
+ else return 1;
+}
+
+/** Tell if a tile is animated or not */
+bool get_anim(short x_c, short y_c, char layer) {
+ char temp = map.tiles[x_c][y_c].flags & 0x00C0;
+ temp>>=6;
+ if(abs(temp)==layer)return (map.tiles[x_c][y_c].data[3] & 0x0001)>0;
+ else return false;
+}
+
+/** Set tile ID */
+void set_tile(short x_c, short y_c, char layer, unsigned short id) {
+ if(layer==0) {
+ id <<= 6;
+ map.tiles[x_c][y_c].data[0] = HIBYTE(id);
+ map.tiles[x_c][y_c].data[1] &= 0x003f;
+ map.tiles[x_c][y_c].data[1] |= LOBYTE(id);
+ } else if(layer==1) {
+ id <<= 4;
+ map.tiles[x_c][y_c].data[1] &= 0x00c0;
+ map.tiles[x_c][y_c].data[1] |= HIBYTE(id);
+ map.tiles[x_c][y_c].data[2] &= 0x000f;
+ map.tiles[x_c][y_c].data[2] |= LOBYTE(id);
+ } else if(layer==2) {
+ id <<= 2;
+ map.tiles[x_c][y_c].data[2] &= 0x00f0;
+ map.tiles[x_c][y_c].data[2] |= HIBYTE(id);
+ map.tiles[x_c][y_c].data[3] &= 0x0003;
+ map.tiles[x_c][y_c].data[3] |= LOBYTE(id);
+ }
+}
+
+/** Return tile ID */
+unsigned short get_tile(short x_c, short y_c, char layer) {
+ unsigned short id;
+ if(layer==0) {
+ id = MAKEWORD(map.tiles[x_c][y_c].data[1] & 0x00c0, map.tiles[x_c][y_c].data[0]);
+ id >>= 6;
+ } else if(layer==1) {
+ id = MAKEWORD(map.tiles[x_c][y_c].data[2] & 0x00f0, map.tiles[x_c][y_c].data[1] & 0x003f);
+ id >>= 4;
+ } else if(layer==2) {
+ id = MAKEWORD(map.tiles[x_c][y_c].data[3] & 0x00fc, map.tiles[x_c][y_c].data[2] & 0x000f);
+ id >>=2;
+ }
+ return id;
+}
diff --git a/src/map.h b/src/map.h
new file mode 100644
index 00000000..4c33928d
--- /dev/null
+++ b/src/map.h
@@ -0,0 +1,89 @@
+/**
+
+ 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
+
+*/
+
+#ifndef _MAP_H
+#define _MAP_H
+
+#define MAP_WIDTH 200
+#define MAP_HEIGHT 200
+#define TILESET_WIDTH 30
+
+#define WALKABLE 0
+#define NOT_WALKABLE 1
+
+/** Struct representing a tile. A tile is composed of 3 layers.
+1st: Ground layer (used for grass, water, ...) -> bit 0-9 of data
+2nd: Fringe layer (objects that are overlapped by the player) -> bit 10-19 of data
+3rd: Over layer (roofs, tree leaves, ...) -> bit 20-29
+Walk flag: tells if a tile is walkable or not -> bit 30
+Animation flag: tells if a tile is animated or not -> bit 31
+
+data field:
+1st byte: [1][1][1][1][1][1][1][1]
+2nd byte: [1][1][2][2][2][2][2][2]
+3rd byte: [2][2][2][2][3][3][3][3]
+4th byte: [3][3][3][3][3][3][W][A]
+
+Legend:
+1 - First layer
+2 - Second layer
+3 - Third layer
+W - Walkability flag
+A - Animated tile flag
+
+flags field:
+[l][l][f][f][f][f][f][f][f]
+
+Legend:
+l - Animated layer
+f - future use
+*/
+struct TILE {
+ char data[4];
+ char flags;
+};
+
+struct MAP {
+ TILE tiles[MAP_WIDTH][MAP_HEIGHT];
+ char tileset[20];
+ char bg_music[20];
+};
+
+bool load_map(char *map_file);
+void set_walk(short x_c, short y_c, bool walkable);
+bool get_walk(short x_c, short y_c);
+unsigned char get_path_walk(unsigned short x, unsigned short y);
+bool get_anim(short x_c, short y_c, char layer);
+void set_tile(short x_c, short y_c, char layer, unsigned short id);
+unsigned short get_tile(short x_c, short y_c, char layer);
+
+/** Return tile x coordinate in tileset */
+inline int get_tile_x(int x, int y, int layer) {
+ return get_tile(x,y,layer)%TILESET_WIDTH;
+}
+/** Return tile y coordinate in tileset */
+inline int get_tile_y(int x, int y, int layer) {
+ return get_tile(x,y,layer)/TILESET_WIDTH;
+}
+
+#endif
diff --git a/src/net/network.cpp b/src/net/network.cpp
new file mode 100644
index 00000000..c8bff09a
--- /dev/null
+++ b/src/net/network.cpp
@@ -0,0 +1,177 @@
+/**
+
+ 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
+
+*/
+
+#include "network.h"
+#ifndef WIN32
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+/** Warning: buffers and other variables are shared,
+ so there can be only one connection active at a time */
+
+int buffer_size = 65536;
+char *in, *out;
+int in_size, out_size;
+
+SOCKET sock;
+SOCKADDR_IN addr;
+// File descriptors attached to socket
+fd_set read_socket;
+fd_set write_socket;
+
+/** Increase size of written data */
+void WFIFOSET(int len) {
+ if(out_size+len>=buffer_size)
+ warning("Output buffer full");
+ else out_size+=len;
+}
+
+/** Convert an address from int format to string */
+char *iptostring(int address) {
+ short temp1, temp2;
+
+ char *temp = (char *)malloc(sizeof(char[20]));
+ temp1 = LOWORD(address);
+ temp2 = HIWORD(address);
+ sprintf(temp, "%i.%i.%i.%i", LOBYTE(temp1), HIBYTE(temp1), LOBYTE(temp2), HIBYTE(temp2));
+ return temp;
+}
+
+/** Open a session with a server */
+SOCKET open_session(const char* address, short port) {
+ #ifdef WIN32
+ WSADATA wsda;
+ #endif
+ struct hostent *server;
+ int ret;
+
+ // Init WinSock and connect the socket
+ #ifdef WIN32
+ WSAStartup(MAKEWORD(2,0), &wsda);
+ #endif
+
+ sock = socket(PF_INET, SOCK_STREAM, 0); // Create socket for current session
+ if(sock==SOCKET_ERROR)return SOCKET_ERROR;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = inet_addr(address);
+ if(addr.sin_addr.s_addr == INADDR_NONE){
+ server = NULL;
+ server = gethostbyname(address);
+ if(server == NULL)return SOCKET_ERROR;
+ memcpy(&addr.sin_addr, server->h_addr_list[0], server->h_length);
+ }
+
+ ret = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if(ret == SOCKET_ERROR)return SOCKET_ERROR;
+
+ // Init buffers
+ in = (char *)malloc(buffer_size);
+ out = (char *)malloc(buffer_size);
+ memset(in, '\0', buffer_size);
+ memset(out, '\0', buffer_size);
+ in_size = 0;
+ out_size = 0;
+ FD_CLR(sock, &read_socket);
+ FD_CLR(sock, &write_socket);
+
+ return sock;
+}
+
+/** Close a session */
+void close_session() {
+ FD_CLR(sock,&read_socket);
+ FD_CLR(sock,&write_socket);
+ closesocket(sock);
+ if(in!=NULL)free(in);
+ if(out!=NULL)free(out);
+ in = NULL;
+ out = NULL;
+ in_size = 0;
+ out_size = 0;
+ WSACleanup();
+}
+
+/** Send and receive data waiting in the buffers */
+void flush() {
+ int ret = 0;
+ void *buf = out; //-kth5
+ timeval time_out;
+
+ // Init the time_out struct to 0s so it won't block
+ time_out.tv_sec=0;
+ time_out.tv_usec=0;
+
+ // Clear file descriptors and set them to socket
+ FD_ZERO(&read_socket);
+ FD_ZERO(&write_socket);
+ FD_SET(sock, &read_socket);
+ FD_SET(sock, &write_socket);
+
+ // Check if socket has available data by evaluating attached file descriptors
+ select(FD_SETSIZE, &read_socket, &write_socket, NULL, &time_out);
+
+ // Send data if available
+ if(FD_ISSET(sock, &write_socket)) {
+ // While there wasn't a error or sent the whole data: handles partial packet send
+ while((ret!=SOCKET_ERROR)&&(out_size>0)) {
+ ret = send(sock, (char *)buf, out_size, 0);
+ /*FILE *file = fopen("log.log","wb");
+
+ fprintf(file, "%s", out[0]);
+ fclose(file);*/
+ // If not the whole data has been sent, empty the buffer from already sent bytes
+ if(ret!=SOCKET_ERROR && ret>0) {
+ buf = (char*)buf+ret; //-kth5
+ out_size -= ret;
+ }
+ }
+ if(ret==SOCKET_ERROR) {
+ error("Socket Error");
+#ifdef WIN32
+ log_int("Error", "socket_error", WSAGetLastError());
+#else
+ log("Error", "socket_error", "Undefined socket error");
+#endif
+ }
+ }
+
+ // Read data, if available
+ if(FD_ISSET(sock, &read_socket)) {
+ /* There's no check for partial received packets because at this level
+ the app doesn't know packet length, but it will done when parsing received data */
+ ret = recv(sock, in+in_size, RFIFOSPACE, 0);
+ if(ret==SOCKET_ERROR) {
+#ifdef WIN32
+ log_int("Error", "socket_error", WSAGetLastError());
+#else
+ log("Error", "socket_error", "Undefined socket error");
+#endif
+ } else RFIFOSET(ret); // Set size of available data to read
+ }
+}
+
+
diff --git a/src/net/network.h b/src/net/network.h
new file mode 100644
index 00000000..5eca3398
--- /dev/null
+++ b/src/net/network.h
@@ -0,0 +1,87 @@
+/**
+
+ 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
+
+*/
+
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#ifndef _NETWORK_H
+#define _NETWORK_H
+
+#ifdef WIN32
+#include <allegro.h>
+#include <winalleg.h>
+#else
+#include "win2linux.h"
+#endif
+#include <stdio.h>
+#include "../log.h"
+#ifdef MACOSX
+#include "win2mac.h"
+#endif
+
+/** Macros to write in output buffer, pos is the location where to write data
+ After you wrote len bytes, you have to use WFIFOSET */
+#define WFIFOSPACE (buffer_size-out_size) // Number of bytes currently written in uotput buffer
+#define WFIFOP(pos) (out+(pos+out_size)) // Return a pointer to a specific location in output buffer
+#define WFIFOB(pos) (*(unsigned char *)(out+pos+out_size)) // Write a byte (1 byte)
+#define WFIFOW(pos) (*(unsigned short *)(out+pos+out_size)) // Write a word (2 byte)
+#define WFIFOL(pos) (*(unsigned int *)(out+pos+out_size)) // Write a long (4 byte)
+//#define WFIFOSET(len) out_size+=len // Increase size of written data
+#ifdef MACOSX
+#define net_b_value(id) (id)
+#define net_w_value(id) DR_SwapTwoBytes(id)
+#define net_l_value(id) DR_SwapFourBytes(id)
+#else
+#define net_b_value(id) (id)
+#define net_w_value(id) (id)
+#define net_l_value(id) (id)
+#endif
+
+
+/** Macros to read from input buffer, pos is the location of data to be read
+ After you read len bytes, you should use RFIFOSKIP */
+#define RFIFOP(pos) (in+(pos)) // Get a pointer from a specific location in input buffer
+#ifdef MACOSX
+#define RFIFOB(pos) ((*(unsigned char*)(in+(pos)))) // Read a byte
+#define RFIFOW(pos) DR_SwapTwoBytes((*(unsigned short*)(in+(pos)))) // Read a word
+#define RFIFOL(pos) DR_SwapFourBytes((*(unsigned int*)(in+(pos)))) // Read a long
+#else
+#define RFIFOB(pos) (*(unsigned char*)(in+(pos))) // Read a byte
+#define RFIFOW(pos) (*(unsigned short*)(in+(pos))) // Read a word
+#define RFIFOL(pos) (*(unsigned int*)(in+(pos))) // Read a long
+#endif
+#define RFIFOSKIP(len) (memcpy(in,in+len,in_size-len));in_size-=len; // Empty len bytes from input buffer
+#define RFIFOSPACE (buffer_size-in_size) // Return input buffer size
+#define RFIFOSET(len) in_size+=len;
+
+void WFIFOSET(int len);
+char *iptostring(int address);
+SOCKET open_session(const char* address, short port);
+void close_session();
+void flush();
+
+extern char *in, *out; // Input, output buffer
+extern int in_size, out_size; // Input, output buffer size
+
+#endif
diff --git a/src/net/protocol.cpp b/src/net/protocol.cpp
new file mode 100644
index 00000000..2c33d092
--- /dev/null
+++ b/src/net/protocol.cpp
@@ -0,0 +1,264 @@
+/**
+
+ 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
+
+*/
+
+#include "protocol.h"
+
+short packet_lengths[] = {
+
+ 10, 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, 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, 0, 0, 0, 0, 0, 0, 0,
+// #0x0040
+ 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, 0, 0, 0, 0,
+ 0, 0, 0, 0, 55, 17, 3, 37, 46, -1, 23, -1, 3,108, 3, 2,
+ 3, 28, 19, 11, 3, -1, 9, 5, 54, 53, 58, 60, 41, 2, 6, 6,
+// #0x0080
+ 7, 3, 2, 2, 2, 5, 16, 12, 10, 7, 29, 23, -1, -1, -1, 0,
+ 7, 22, 28, 2, 6, 30, -1, -1, 3, -1, -1, 5, 9, 17, 17, 6,
+ 23, 6, 6, -1, -1, -1, -1, 8, 7, 6, 7, 4, 7, 0, -1, 6,
+ 8, 8, 3, 3, -1, 6, 6, -1, 7, 6, 2, 5, 6, 44, 5, 3,
+// #0x00C0
+ 7, 2, 6, 8, 6, 7, -1, -1, -1, -1, 3, 3, 6, 6, 2, 27,
+ 3, 4, 4, 2, -1, -1, 3, -1, 6, 14, 3, -1, 28, 29, -1, -1,
+ 30, 30, 26, 2, 6, 26, 3, 3, 8, 19, 5, 2, 3, 2, 2, 2,
+ 3, 2, 6, 8, 21, 8, 8, 2, 2, 26, 3, -1, 6, 27, 30, 10,
+// #0x0100
+ 2, 6, 6, 30, 79, 31, 10, 10, -1, -1, 4, 6, 6, 2, 11, -1,
+ 10, 39, 4, 10, 31, 35, 10, 18, 2, 13, 15, 20, 68, 2, 3, 16,
+ 6, 14, -1, -1, 21, 8, 8, 8, 8, 8, 2, 2, 3, 4, 2, -1,
+ 6, 86, 6, -1, -1, 7, -1, 6, 3, 16, 4, 4, 4, 6, 24, 26,
+// #0x0140
+ 22, 14, 6, 10, 23, 19, 6, 39, 8, 9, 6, 27, -1, 2, 6, 6,
+ 110, 6, -1, -1, -1, -1, -1, 6, -1, 54, 66, 54, 90, 42, 6, 42,
+ -1, -1, -1, -1, -1, 30, -1, 3, 14, 3, 30, 10, 43, 14,186,182,
+ 14, 30, 10, 3, -1, 6,106, -1, 4, 5, 4, -1, 6, 7, -1, -1,
+// #0x0180
+ 6, 3,106, 10, 10, 34, 0, 6, 8, 4, 4, 4, 29, -1, 10, 6,
+ 90, 86, 24, 6, 30,102, 9, 4, 8, 4, 14, 10, 4, 6, 2, 6,
+ 3, 3, 35, 5, 11, 26, -1, 4, 4, 6, 10, 12, 6, -1, 4, 4,
+ 11, 7, -1, 67, 12, 18,114, 6, 3, 6, 26, 26, 26, 26, 2, 3,
+// #0x01C0
+ 2, 14, 10, -1, 22, 22, 4, 2, 13, 97, 0, 9, 9, 29, 6, 28,
+ 8, 14, 10, 35, 6, 8, 4, 11, 54, 53, 60, 2, -1, 47, 33, 6,
+ 30, 8, 34, 14, 2, 6, 26, 2, 28, 81, 6, 10, 26, 2, -1, -1,
+ -1, -1, 20, 10, 32, 9, 34, 14, 2, 6, 48, 56, -1, 4, 5, 10,
+// #0x200
+ 26, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 19,
+
+};
+
+/** Packet length by id */
+short get_length(short id) {
+ return packet_lengths[id];
+}
+
+/** Decodes dest x coord */
+unsigned short get_dest_x(char *data) {
+ short temp;
+ temp = MAKEWORD(data[3], data[2] & 0x000f);
+ temp >>= 2;
+ return temp;
+}
+
+/** Decodes dest y coord */
+unsigned short get_dest_y(char *data) {
+ short temp;
+ temp = MAKEWORD(data[4], data[3] & 0x0003);
+ return temp;
+}
+
+/** Decodes src x coord */
+unsigned short get_src_x(char *data) {
+ short temp;
+ temp = MAKEWORD(data[1], data[0]);
+ temp >>= 6;
+ return temp;
+}
+
+/** Decodes src y coord */
+unsigned short get_src_y(char *data) {
+ short temp;
+ temp = MAKEWORD(data[2], data[1] & 0x003f);
+ temp >>= 4;
+ return temp;
+}
+
+/** Decodes src direction */
+unsigned char get_src_direction(char data) {
+ data >>= 4;
+ return data;
+}
+
+/** Decodes dest direction */
+unsigned char get_dest_direction(char data) {
+ return data & 0x000f;
+}
+
+/** Decodes x coord */
+unsigned short get_x(char *data) {
+ short temp;
+ temp = MAKEWORD(data[1] & 0x00c0, data[0] & 0x00ff);
+ temp >>= 6;
+ return temp;
+}
+
+/** Decodes y coord */
+unsigned short get_y(char *data) {
+ short temp;
+ if(!data)error("Corrupted data");
+ temp = MAKEWORD(data[2] & 0x00f0, data[1] & 0x003f);
+ if(!temp)error("Corrupted data");
+ temp >>= 4;
+ return temp;
+}
+
+/** Decodes direction */
+unsigned char get_direction(char *data) {
+ char temp;
+ temp = data[2] & 0x000f;
+ return temp;
+}
+
+/** Encodes coords and direction in 3 bytes data */
+void set_coordinates(char *data, unsigned short x, unsigned short y, unsigned char direction) {
+ short temp;
+ temp = x;
+ temp <<= 6;
+ data[0] = 0;
+ data[1] = 1;
+ data[2] = 2;
+ data[0] = HIBYTE(temp);
+ data[1] = LOBYTE(temp);
+ temp = y;
+ temp <<= 4;
+ data[1] |= HIBYTE(temp);
+ data[2] = LOBYTE(temp);
+ data[2] |= direction;
+}
+
+/** Initialize connection with map server */
+void map_start() {
+ // Connect to map server
+ if(open_session(iptostring(map_address), map_port)==SOCKET_ERROR) {
+ warning("Unable to connect to map server");
+ state = LOGIN;
+ ok("Error", "Unable to connect to map server");
+ return;
+ }
+
+ // Send login infos
+ WFIFOW(0) = net_w_value(0x0072);
+ WFIFOL(2) = net_l_value(account_ID);
+ WFIFOL(6) = net_l_value(char_ID);
+ WFIFOL(10) = net_l_value(session_ID1);
+ WFIFOL(14) = net_l_value(session_ID2);
+ WFIFOB(18) = net_b_value(sex);
+ WFIFOSET(19);
+
+ while((in_size<4)||(out_size>0))flush();
+ RFIFOSKIP(4);
+
+ while(in_size<2)flush();
+
+ if(RFIFOW(0)==0x0073) {
+ while(in_size<11)flush();
+ x = get_x(RFIFOP(6));
+ y = get_y(RFIFOP(6));
+ log_int("Player", "x", x);
+ log_int("Player", "y", y);
+ direction = get_direction(RFIFOP(6));
+ log_int("Player", "direction", direction);
+ RFIFOSKIP(11);
+ } else if(0x0081) {
+ warning("Map server D/C");
+ } else error("Unknown packet: map_start");
+ // Send "map loaded"
+ WFIFOW(0) = net_w_value(0x007d);
+ WFIFOSET(2);
+ while(out_size>0)flush();
+}
+
+/** Requests to walk */
+void walk(unsigned short x, unsigned short y, unsigned char direction) {
+ char temp[3];
+ set_coordinates(temp, x, y, direction);
+ WFIFOW(0) = net_w_value(0x0085);
+ memcpy(WFIFOP(2), temp, 3);
+ WFIFOSET(5);
+}
+
+/** Request to speak */
+void speak(char *speech) {
+ int len = (int)strlen(speech);
+ WFIFOW(0) = net_w_value(0x008c);
+ WFIFOW(2) = net_w_value(len+4);
+ memcpy(WFIFOP(4), speech, len);
+ WFIFOSET(len+4);
+}
+
+/** request action */
+void action(short type, int id) {
+ WFIFOW(0) = net_w_value(0x0089);
+ WFIFOL(2) = net_l_value(id);
+ WFIFOB(6) = net_l_value(type);
+ WFIFOSET(7);
+}
+
+
+/** Request to attack */
+void attack(unsigned short x, unsigned short y, unsigned char direction) {
+ int monster_id = 0;
+
+ if(direction==2) {
+ for(int j=-1;j<2;j++)
+ for(int i=-1;i<1;i++) {
+ monster_id = find_monster(x+i, y+j);
+ if(monster_id!=0)
+ action(0x07, monster_id);
+ }
+ } else if(direction==6) {
+ for(int j=-1;j<2;j++)
+ for(int i=0;i<2;i++) {
+ monster_id = find_monster(x+i, y+j);
+ if(monster_id!=0)
+ action(0x07, monster_id);
+ }
+ } else if(direction==4) {
+ for(int j=-1;j<1;j++)
+ for(int i=-1;i<2;i++) {
+ monster_id = find_monster(x+i, y+j);
+ if(monster_id!=0)
+ action(0x07, monster_id);
+ }
+ } else if(direction==0) {
+ for(int j=0;j<1;j++)
+ for(int i=-1;i<2;i++) {
+ monster_id = find_monster(x+i, y+j);
+ if(monster_id!=0)
+ action(0x07, monster_id);
+ }
+ }
+}
+
diff --git a/src/net/protocol.h b/src/net/protocol.h
new file mode 100644
index 00000000..60293e4a
--- /dev/null
+++ b/src/net/protocol.h
@@ -0,0 +1,57 @@
+/**
+
+ 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
+
+*/
+#ifdef WIN32
+ #pragma warning (disable:4312)
+#endif
+
+#ifndef _PROTOCOL_H
+#define _PROTOCOL_H
+
+#include <allegro.h>
+#ifdef WIN32
+#include <winalleg.h>
+#include <windows.h>
+#else
+#include "win2linux.h"
+#endif
+
+#include "../main.h"
+#include "../being.h"
+
+short get_length(short id);
+unsigned short get_x(char *data);
+unsigned short get_y(char *data);
+unsigned char get_direction(char *data);
+unsigned short get_src_x(char *data);
+unsigned short get_src_y(char *data);
+unsigned char get_src_direction(char data);
+unsigned short get_dest_x(char *data);
+unsigned short get_dest_y(char *data);
+unsigned char get_dest_direction(char data);
+void set_coordinates(char *data, unsigned short x, unsigned short y, unsigned char direction);
+void map_start();
+void walk(unsigned short x, unsigned short y, unsigned char direction);
+void speak(char *speech);
+void attack(unsigned short x, unsigned short y, unsigned char direction);
+void action(short, int);
+#endif
diff --git a/src/net/win2linux.h b/src/net/win2linux.h
new file mode 100644
index 00000000..71737a58
--- /dev/null
+++ b/src/net/win2linux.h
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef MACOSX
+#include <malloc.h>
+#endif
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+#define MAKEWORD(low,high) \
+ ((WORD)(((BYTE)(low)) | ((WORD)((BYTE)(high))) << 8))
+#define closesocket(a) close(a)
+#define SOCKET int
+#define SOCKET_ERROR -1
+#define SOCKADDR_IN struct sockaddr_in
+typedef struct sockaddr SOCKADDR;
+typedef SOCKADDR * LPSOCKADDR;
+#define WSACleanup() ;
+
+
+
+typedef unsigned short WORD;
+typedef unsigned long int LWORD;
+typedef unsigned char BYTE;
+#define LOBYTE(w) ((BYTE) (w) )
+#define HIBYTE(w) ((BYTE) (((WORD)(w)) >> 8) )
+#define LOWORD(l) ((WORD) (l) )
+#define HIWORD(l) ((WORD) (((LWORD)(l)) >> 16) )
+#define HANDLE int
+#define HANDLE int
+#define PHANDLE int
+#define SMALL_RECT int
+//#define WORD int
+#define DWORD int
+#define PDWORD int
+#define BOOL int
+#define LPBOOL int
+#define LPSTR int
+#define LPTSTR int
+#define LPCTSTR int
+#define LPDWORD int
+#define LPVOID int
+#define WINAPI
+
+#define LOBYTE(w) ((BYTE) (w) )
+#define HIBYTE(w) ((BYTE) (((WORD)(w)) >> 8) )
+#define LPTHREAD_START_ROUTINE void *(*)(void *)
+#define CloseHandle close
diff --git a/src/net/win2mac.cpp b/src/net/win2mac.cpp
new file mode 100644
index 00000000..be4bad1d
--- /dev/null
+++ b/src/net/win2mac.cpp
@@ -0,0 +1,42 @@
+#include "win2mac.h"
+
+
+void dummy()
+{
+
+printf("hej\n");
+}
+
+UInt32 DR_SwapFourBytes(UInt32 dw)
+{
+UInt32 tmp;
+tmp = (dw & 0x000000FF);
+tmp = ((dw & 0x0000FF00) >> 0x08) | (tmp << 0x08);
+tmp = ((dw & 0x00FF0000) >> 0x10) | (tmp << 0x08);
+tmp = ((dw & 0xFF000000) >> 0x18) | (tmp << 0x08);
+return (tmp);
+}
+
+UInt16 DR_SwapTwoBytes(UInt16 w)
+{
+UInt16 tmp;
+tmp = (w & 0x00FF);
+tmp = ((w & 0xFF00) >> 0x08) | (tmp << 0x08);
+return(tmp);
+}
+
+char* SwapChar(char charlist[])
+{
+for(int i =0; i< 24/2; i++)
+ SWAP(charlist[i],charlist[24-i]);
+return charlist;
+}
+
+/*
+char* SwapChar(char charlist[])
+{
+for(int i =0; i< sizeof(charlist)*4/2; i++)
+ SWAP(charlist[i],charlist[sizeof(charlist)*4-i]);
+return charlist;
+}
+*/ \ No newline at end of file
diff --git a/src/net/win2mac.h b/src/net/win2mac.h
new file mode 100644
index 00000000..72ae9fd9
--- /dev/null
+++ b/src/net/win2mac.h
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+#define UInt16 unsigned short int
+#define INT16 short int
+#define UInt32 unsigned long int
+#define INT32 long int
+#define SWAP( a, b ) { char c; c=a; a=b; b=c; }
+
+#ifndef _MAC_H
+#define _MAC_H
+void dummy();
+UInt32 DR_SwapFourBytes(UInt32 dw);
+UInt16 DR_SwapTwoBytes(UInt16 w);
+char* SwapChar(char charlist[]);
+#endif
+
diff --git a/src/sound/sound.cpp b/src/sound/sound.cpp
new file mode 100644
index 00000000..105959ba
--- /dev/null
+++ b/src/sound/sound.cpp
@@ -0,0 +1,269 @@
+/**
+
+ 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
+
+*/
+
+/**
+ rewrite of non-existend sdl-soundengine using allegro
+
+ Author: kth5 aka Alexander Baldeck
+ pipe your question, suggestions and flames to: kth5@gawab.com
+*/
+
+#ifdef WIN32
+ #pragma warning(disable:4312)
+#endif
+
+#include <allegro.h>
+
+
+ #include <jgmod.h>
+ #include "sound.h"
+
+/**
+ install the sound engine
+ int voices -> overall reserved voices
+ int mod_voices -> voices dedicated for mod-playback
+
+ NOTE:
+ overall voices must not be less or equal to the
+ specified amount of mod_voices!
+ if mod-voices is too low some mods will not sound
+ correctly since a couple of tracks are not going
+ to be played along w/ the others. so missing ins-
+ truments can be a result.
+ 32/20 sounds realistic here.
+*/
+void TmwSound::Init(int voices, int mod_voices) {
+ isOk = -1;
+
+ if(mod_voices >= voices)
+ throw("No voices left for SFX! Sound will be disabled!");
+
+ install_timer();
+ reserve_voices (voices, -1);
+
+ #ifdef WIN32
+ if (install_sound (DIGI_AUTODETECT, MIDI_AUTODETECT, NULL) < 0)
+ #else
+ if (install_sound (DIGI_AUTODETECT, MIDI_NONE, NULL) < 0)
+ #endif
+ throw("Could not initialize sound... :-(");
+
+
+ if (install_mod (mod_voices) < 0)
+ throw("Could not install MOD player... :-(");
+
+ mod = NULL;
+ mid = NULL;
+ sfx = NULL;
+
+ pan = 128;
+ pitch=1000;
+
+ isOk = 0;
+}
+
+/**
+ set the volume value-range: 0-255
+ int digi -> for digital playback
+ int mid -> for midi playback
+ int mod -> for... aw, you guess ^^
+
+ NOTE:
+ all values may only be between 0-255 where 0 means
+ muted.
+*/
+void TmwSound::SetVol(int digi, int mid, int mod) {
+ if(isOk==-1)
+ return;
+ set_volume(digi, mid);
+ set_mod_volume(mod);
+ set_hardware_volume(digi, mid);
+
+ if(isMaxVol(vol_digi + digi)==false) vol_digi += digi;
+ if(isMaxVol(vol_midi + mid) ==false) vol_midi += mid;
+ if(isMaxVol(vol_mod + mod) ==false) vol_mod += mod;
+}
+
+/**
+ adjusts current volume
+ int digi -> for digital playback
+ int mid -> for midi playback
+ int mod -> for... aw, you guess ^^
+
+ NOTE:
+ all values may only be between 0-255 where 0 means
+ muted.
+*/
+void TmwSound::SetAdjVol(int adigi, int amid, int amod) {
+ if(isOk==-1)
+ return;
+ set_volume(vol_digi + adigi, vol_midi + amid);
+ set_mod_volume(vol_mod + amod);
+
+ if(isMaxVol(vol_digi + adigi)==false) vol_digi += adigi;
+ if(isMaxVol(vol_midi + amid) ==false) vol_midi += amid;
+ if(isMaxVol(vol_mod + amod) ==false) vol_mod += amod;
+}
+
+/**
+ start BGM using a midi file
+ char *in -> full path of midi file
+ int loop -> how many times should the midi be looped? (-1 = infinite)
+
+ NOTE:
+ playing midi does not steal away any voices but
+ does not work w/ most soundcards w/o software
+ emulation. this means than linux-users will most
+ probably be left out. do not use this unless we
+ find a way to always get it to work. :-)
+
+ at this point of time only standard RMI midi files
+ can be played. so no m$ extensions like GS and stuff.
+*/
+void TmwSound::StartMIDI(char *in, int loop) {
+ if(isOk==-1)
+ return;
+
+ mid = load_midi(in);
+ if (!mid) {
+ isOk=-1;
+ throw("Could not load MIDI file!");
+ }
+
+ play_midi(mid, TRUE);
+}
+
+/**
+ start BGM using a mod file
+ char *in -> full path of mod file
+ int loop -> how many times should the midi be looped? (-1 = infinite)
+
+ NOTE:
+ playing mod is a pretty good choice. most of the work
+ is being done by the cpu so it's not dependend on the
+ sound-card how things sound as long as it works. ;-)
+
+ JGMOD supports several formats:
+ MOD
+ S3M
+ XM
+ Unreal
+ and S3M (in UMX extension)
+*/
+void TmwSound::StartMOD(char * in, int loop) {
+ if(isOk==-1)
+ return;
+
+ mod = load_mod(in);
+ if(!mod) {
+ isOk=-1;
+ throw("Error reading MOD file...");
+ }
+ play_mod(mod, TRUE);
+}
+
+/**
+ stop all currently running BGM tracks
+
+ NOTE:
+ you need to stop all playback when you want to
+ switch from mod to midi. playing a new track is
+ usually possibe simply by calling StartMIDI() ir
+ SartMOD() again.
+ passing NULL to the playing functions only means
+ to make playback stop.
+*/
+void TmwSound::StopBGM() {
+ if(isOk==-1)
+ return;
+
+ play_midi(NULL,-1);
+ stop_mod();
+
+ mod = NULL;
+ mid = NULL;
+}
+
+/**
+ play short sample usually for sfx
+ char * in -> full path to the sample file
+ (int wavid -> the id of the preloaded wav file (not implemented yet))
+ int pan -> panning of the sound, values can be 0-255 where 128 is
+ the middle
+
+ NOTE:
+ later on this will be a subsequent call to another
+ function that preloads all wavs corresponding to
+ the current area (e.g. monster screams) to memory.
+ right now the function loads the file from hdd
+ everytime you want it to be played. this is kind of
+ resource intensive even though most OS'ses cache a
+ already loaded file for some time.
+
+ allegro supports different formats but this is not
+ stated clear enough - these will work for sure:
+ WAV
+ VOC
+
+ i don't know what kind of samples are necessary so we
+ need to test this thoroughly.
+*/
+void TmwSound::StartWAV(char * in, int pan) {
+ if(isOk==-1)
+ return;
+
+ sfx = load_sample(in);
+ if (!sfx)
+ throw("Error reading WAV file...");
+
+ play_sample(sfx, vol_digi, pan, pitch, FALSE);
+}
+
+/**
+ deinstall all sound functionality
+
+ NOTE:
+ normally you won't need to call this since this is
+ done by allegro when shutting itself down. but if
+ you find a reason to delete the sound-engine from
+ memory (e.g. garbage-collection) feel free to use
+ it. :-P
+*/
+int TmwSound::Close(void) {
+ if(isOk==-1)
+ return -1;
+ mod = NULL;
+ mid = NULL;
+ sfx = NULL;
+
+ remove_sound();
+ isOk = -1;
+ return 0;
+}
+
+/** PRIVATE */
+
+bool TmwSound::isMaxVol(int vol) {
+ if( vol > 0 && vol < 255 ) return false;
+ else return true;
+}
diff --git a/src/sound/sound.h b/src/sound/sound.h
new file mode 100644
index 00000000..12300e58
--- /dev/null
+++ b/src/sound/sound.h
@@ -0,0 +1,83 @@
+/**
+
+ 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
+
+*/
+
+#ifndef __SOUND_H
+#define __SOUND_H
+
+#ifdef WIN32
+ #pragma warning(disable:4312)
+#endif
+#include <allegro.h>
+#include <jgmod.h>
+#include <string>
+using namespace std;
+
+/**
+ rewrite of non-existend sdl-soundengine using allegro
+
+ Author: kth5 aka Alexander Baldeck
+ pipe your question, suggestions and flames to: kth5@gawab.com
+
+ NOTE:
+ i documented all functions in their implementation. ;-)
+*/
+
+class TmwSound {
+ public:
+ void Init(int, int);
+ int Close();
+
+ void StartMIDI(char *, int);
+ void StartMOD(char *, int);
+ void StopBGM();
+
+ void StartWAV(char *, int);
+ void SetVol(int, int, int);
+ void SetAdjVol(int adigi, int amid, int amod);
+
+ TmwSound() {isOk=-1;}
+ ~TmwSound() {StopBGM(); Close();}; // if allegros shuts down or object is deleted
+ // any BGM is stopped and SFX runout
+ private:
+ int isOk; // initial value is -1 which means error.
+ // you can only play sounds and bgm if this is 0.
+ // should be the case after calling Init()
+ // successfully
+
+ MIDI * mid;
+ JGMOD * mod;
+ SAMPLE * sfx;
+
+ int pan;
+ int pitch;
+
+ int ret;
+ int vol_digi;
+ int vol_midi;
+ int vol_mod;
+
+ bool isMaxVol(int);
+};
+
+
+#endif