/**
* @class World
* @brief Represents the game world
* @author Samuel Kaufman
* @date 2002
*/
/**
* @class Block
* @brief Represents a single block within the map
* @author Samuel Kaufman
* @date 2002
*/
/**
* @class Cell
* @brief Represents a single cell within a map block
* @author Samuel Kaufman
* @date 2002
*/
/*****
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*****/
// Debugging variables
#define TARGETZ 10
#define STDH 512
#define TDH 200
#define CalcBID(x,y) ((x*STDH)+y)
#define CalcTDBID(x,y) ((x*TDH)+y)
#include "uop.h"
#include <SDL/SDL.h>
#include <iostream>
#include <fstream>
#include <string>
#include <string.h>
#include "artfactory.h"
#include "sprite.h"
#include "tiledata.h"
#include "uopconfig.h"
#include "world.h"
#include "entity.h"
extern SDL_Surface *screen;
extern TileData *tileData;
extern UOPConfig *config;
extern World *world;
/**
* Check if entities are in right rendering order.
*/
bool Cell::right_order(){
list<Entity*>::iterator cur;
list<Entity*>::iterator prev;
for (cur=entities.begin(),prev=cur++; cur != entities.end(); cur++,prev++)
{
if( (**prev) > (**cur)) return false;
}
return true;
}
/**
* Adds specified entity to cell.
*/
void Cell::add(Entity *entity)
{
list<Entity*>::iterator cur = entities.begin();
if (entity->inCell)
entity->inCell->remove(entity);
entity->inCell = this;
if (entities.empty() || ((**cur) > (*entity)))
{
entities.push_front(entity);
assert(right_order());
return;
}
for (; cur != entities.end(); cur++)
{
if ((**cur) > (*entity))
{
entities.insert(cur, entity);
assert(right_order());
return;
}
}
entities.push_back(entity);
assert(right_order());
}
/**
* Will blit all entities within the cell to the screen.
* @param x The middle X location on the screen to blit.
* @param y The Y location on the screen where a land tile
* at zero altitude would be blit, should it exist.
*/
void Cell::blit(int x, int y)
{
if (entities.empty())
return;
for (list<Entity*>::iterator cur = entities.begin();
cur != entities.end(); cur++)
{
(*cur)->blit(x, y-((*cur)->z-TARGETZ)*4);
}
}
/**
* A factory production function that will load
* needed cell data from the map file.
* @param bid The block ID; usually produced with
* the CalcBID or CalcTDBID macros.
* @param tdmap Wether or not to read data from the
* Ilshenar (Third Dawn) map.
* @param block A reference to the block to store
* data in.
*/
void Block::produce(Uint32 bid, bool tdmap, Block &block)
{
ifstream *mfile;
ifstream *sifile;
ifstream *statfile;
if (tdmap) {
if (!world->tdmapfile.is_open() ||
!world->tdstaidxfile.is_open() ||
!world->tdstaticsfile.is_open())
return;
mfile = &world->tdmapfile;
sifile = &world->tdstaidxfile;
statfile = &world->tdstaticsfile;
}
else {
mfile = &world->mapfile;
sifile = &world->staidxfile;
statfile = &world->staticsfile;
}
mfile->seekg((bid*196)+4);
sifile->seekg(bid*12);
for (int cy = 0; cy < 8; cy++)
{
for (int cx = 0; cx < 8; cx++)
{
LandTile *tile = new LandTile;
Uint16 color;
mfile->read((char*)&color, 2);
mfile->read((char*)&tile->z, 1);
tile->index = color;
block.cells[cx][cy].landTile = tile;
block.cells[cx][cy].add(tile);
}
}
// Load static objects into the block
Uint32 staticlookup, staticlength;
sifile->read((char*)&staticlookup, 4);
sifile->read((char*)&staticlength, 4);
if (staticlookup != 0xffffffff)
{
statfile->seekg(staticlookup);
for (unsigned int cs = 0; cs < (staticlength/7); cs++)
{
Uint16 oid;
Uint8 x, y;
Sint8 alt;
statfile->read((char*)&oid, 2);
statfile->read((char*)&x, 1);
statfile->read((char*)&y, 1);
statfile->read((char*)&alt, 1);
statfile->seekg(2, ios::cur);
Static *object = new Static;
object->index = 0x4000 + oid;
object->z = alt;
if ((x < 8) && (y < 8))
block.cells[x][y].add(object);
else
cerr << "Warning: Static object ignored because of"
<< " invalid coordinates." << endl;
}
}
block.id = bid;
block.tdmap = tdmap;
block.rendered = false;
}
void Block::recycle(Block &block)
{
block.~Block();
}
/**
* Will graphically render all cells inside the
* block by calling LandTile::render().
*/
void Block::renderTiles()
{
char alt;
int x,y;
Block *b2;
Block *b3;
Block *b4;
if (!tdmap) {
b2 = &world->mapBlocks[id+STDH];
b3 = &world->mapBlocks[id+STDH+1];
b4 = &world->mapBlocks[id+1];
}
else {
b2 = &world->mapBlocksTD[id+TDH];
b3 = &world->mapBlocksTD[id+TDH+1];
b4 = &world->mapBlocksTD[id+1];
}
for (y=0;y<7;y++)
for (x=0;x<7;x++)
{
alt=cells[x][y].landTile->z;
int ty2=22+((alt-cells[x+1][y].landTile->z)<<2);
int ty3=43+((alt-cells[x+1][y+1].landTile->z)<<2);
int ty4=22+((alt-cells[x][y+1].landTile->z)<<2);
cells[x][y].landTile->render(ty2, ty3, ty4);
}
for (x=0;x<7;x++)
{
alt=cells[x][7].landTile->z;
int ty2=22+((alt-cells[x+1][7].landTile->z)<<2);
int ty3=43+((alt-b4->cells[x+1][0].landTile->z)<<2);
int ty4=22+((alt-b4->cells[x][0].landTile->z)<<2);
cells[x][7].landTile->render(ty2, ty3, ty4);
}
for (y=0;y<7;y++)
{
alt=cells[7][y].landTile->z;
int ty2=22+((alt-b2->cells[0][y].landTile->z)<<2);
int ty3=43+((alt-b2->cells[0][y+1].landTile->z)<<2);
int ty4=22+((alt-cells[7][y+1].landTile->z)<<2);
cells[7][y].landTile->render(ty2, ty3, ty4);
}
alt=cells[7][7].landTile->z;
int ty2=22+((alt-b2->cells[0][7].landTile->z)<<2);
int ty3=43+((alt-b3->cells[0][0].landTile->z)<<2);
int ty4=22+((alt-b4->cells[7][0].landTile->z)<<2);
cells[7][7].landTile->render(ty2, ty3, ty4);
rendered = true;
}
World::World() : artSprites(*(new ArtFactory(config->encapDatLoc("artidx.mul"), config->encapDatLoc("art.mul")))), mapBlocks(256)
{
/*
string artidxname = config->encapDatLoc("artidx.mul");
artidx.open(artidxname.c_str(), ios::in|ios::binary);
if (!artidx.is_open())
{
cerr << "Couldn't open " << artidxname << endl;
exit(1);
}
string artfilename = config->encapDatLoc("art.mul");
artfile.open(artfilename.c_str(), ios::in|ios::binary);
if (!artfile.is_open())
{
cerr << "Couldn't open " << artfilename << endl;
exit(1);
}
*/
//artSprites = (new Cache<Uint32, Sprite, ArtFactory> (*(new ArtFactory(config->encapDatLoc("artidx.mul"), config->encapDatLoc("art.mul")))));
string mapfilestr = config->encapDatLoc("map0.mul");
mapfile.open(mapfilestr.c_str(), ios::in|ios::binary);
if (!mapfile.is_open())
{
cerr << "Couldn't open " << mapfilestr << endl;
exit(1);
}
string staticsfilestr = config->encapDatLoc("statics0.mul");
staticsfile.open(staticsfilestr.c_str(), ios::in|ios::binary);
if (!staticsfile.is_open())
{
cerr << "Couldn't open " << staticsfilestr << endl;
exit(1);
}
string tdstaticsfilestr = config->encapDatLoc("statics2.mul");
tdstaticsfile.open(tdstaticsfilestr.c_str(), ios::in|ios::binary);
string staidxfilestr = config->encapDatLoc("staidx0.mul");
staidxfile.open(staidxfilestr.c_str(), ios::in|ios::binary);
if (!staidxfile.is_open())
{
cerr << "Couldn't open " << staidxfilestr << endl;
exit(1);
}
string tdstaidxfilestr = config->encapDatLoc("staidx2.mul");
tdstaidxfile.open(tdstaidxfilestr.c_str(), ios::in|ios::binary);
focus = NULL;
is_paused = true;
}
World::~World()
{
//artidx.close();
//artfile.close();
mapfile.close();
tdmapfile.close();
staidxfile.close();
tdstaidxfile.close();
staticsfile.close();
tdstaticsfile.close();
}
/**
* Locates a cell within the map by global
* coordinates.
* @param globalX The global map X position of the cell.
* @param globalY The global map Y position of the cell.
* @param tdmap Wether or not the cell is in Ilshenar.
* @param renderBlock Wehter or not the cell's containing
* block should be graphically rendered and stored in memory.
*/
Cell *World::getCell(Uint16 globalX, Uint16 globalY, bool tdmap, bool renderBlock)
{
Uint16 blockx = globalX / 8;
Uint16 blocky = globalY / 8;
Uint8 localx = globalX - (blockx*8);
Uint8 localy = globalY - (blocky*8);
if (tdmap) {
if (renderBlock&& !mapBlocksTD[CalcTDBID(blockx, blocky)].rendered)
mapBlocksTD[CalcTDBID(blockx, blocky)].renderTiles();
return &mapBlocksTD[CalcTDBID(blockx, blocky)].cells[localx][localy];
}
else {
if (renderBlock && !mapBlocks[CalcBID(blockx, blocky)].rendered)
mapBlocks[CalcBID(blockx, blocky)].renderTiles();
return &mapBlocks[CalcBID(blockx, blocky)].cells[localx][localy];
}
}
bool World::paused() const{
return is_paused;
}
void World::pause(){
is_paused = true;
}
void World::unpause(){
is_paused = false;
}