/*
 * server/Zone.h:
 *
 * Copyright (C) 2000 John Watson, jwatson@tempusmud.com
 * 
 * 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.
 * 
 */

#ifndef __Zone_h__
#define __Zone_h__

#include "Entity.h"

#include <vector>

#include "../util/Array.h"

/** 
 * a rectangular, 2d map
 */

class Zone : public Entity {

        Array<class Sector *>        _sectors;
        Array<float *>               _vertexes;
        Array<class LineDef *>       _lines;
        Array<class SideDef *>       _sides;
        Array<const char *>          _texnames;
        Array<class Lightmap *>      _lightmaps;
        Array<class LightSource *>   _lights;
        Array<class SectorSpecial *> _sectSpecials;
        Array<class Script *>        _scripts;
        vector<class StartPoint *>   _startPoints;
        vector<class ZoneCmd *>      _cmds;

        bool _isVisLoaded;

        bool _useDynamicLights;
        unsigned int _cur_tick;

protected:
        void setFloorCeilingSectors( class Entity * ent ) const;

public:

        inline class World * getWorld() { return (class World*) getContainer(); }

        void spawnCharacter( class Character * ch, int start_point ) const;
        
        inline bool getUseDynamicLights() const { return _useDynamicLights; }
        void setUseDynamicLights( bool b );
        
        class Entity * setTargetEntity( class Character * ch, float angle_z, float angle_x ) const;
        
        const unsigned char * setEntityIllumination( class Entity * ent ) const;
        void modifyDynamicLightmap( const class Entity *ent ) const;
        void updateDynamicLightmaps() const;
        
        void paintSectorLightmaps( const int lightrange,
                                   const int * lightPt,
                                   const class Sector * s ) const;
        
        void paintWallLightmaps( const class Entity * ent,
                                 const int * lightPt,
                                 const class LineDef * line ) const;

        bool createVisibleSets();
        bool createVisibleSectorSets();
        bool createVisibleSurfaceSets();
        bool createVisibleLineSets();
        
        bool illuminate( unsigned int sample_size, unsigned int texels,
                         float scatter_threshold,
                         float scatter_minval );
        bool illuminateSectors( unsigned int sample_size, 
                                unsigned int texels,
                                float scatter_threshold,
                                float scatter_minval,
                                vector<class Lightmap *> & blm   );
        bool illuminateWalls( unsigned int sample_size, 
                              unsigned int texels, 
                              vector<class Lightmap *> & blm   );
        void illuminateWall( class Lightmap * lm, 
                             const class LineDef * line,
                             const class LightSource * lt,
                             const float * origin, 
                             unsigned int sample_size,
                             const float * extents );
        
        bool writeZone( ostream &os );
        
        Zone( const char * name, const char * alias );
        virtual ~Zone();
        
        bool addEntity( class Entity * ent );
        bool removeEntity( class Entity * ent );
        
        bool loadAllData();
        void setInitialStates();

        void loadCmds( istream & is );
        void loadEntity( istream & is );

        void executeCmds( class World * world );
        
        const class Array<float *> & getVertexes() const { return _vertexes; }
        const class Array<Sector *> & getSectors() const { return _sectors; }
        const class Array<SectorSpecial *> & getSectSpecials() const { return _sectSpecials; }
        const class Array<Script *> & getScripts() const { return _scripts; }
        const class Array<LineDef *> & getLines() const { return _lines; }
        const class Array<SideDef *> & getSides() const { return _sides; }
        const class Array<const char*> &getTexnames() const { return _texnames; }
        const class Array<class Lightmap *> & getLightmaps() const { return _lightmaps; }

        void printStatistics( const char * comment = 0 ) const;

        bool checkWallCollision( class Entity * ent, float * scale, float * colliderNormal, bool * skip );
        
        class Sector * findSector( const class Entity * ent ) const;
        class Sector * findSector( const float * pt ) const;

        void physicsUpdateContents( unsigned int tick );

        void updateSectorSpecials( unsigned int tick );
        void triggerLine( class Entity * ent, const class LineDef * line );
        void triggerSectorSpecials( int tag, int value );

        bool isRayBlocked( const float * pt1, const float * pt2, 
                           const class Sector * target_sector,
                           const class LineDef * self_line,
                           const class Sector * self_sector,
                           float * blocked_dist ) const;
        
        bool isVisLoaded() const { return _isVisLoaded; }
        
        bool sectorsCanSee( const class Sector * s1, const class Sector * s2 ) const;
        bool mergePVS( class Zone & other );
        bool spliceZone( const class Zone & splice );

        struct Header {
                unsigned short num_verts;
                unsigned short num_sides;
                unsigned short num_lines;
                unsigned short num_scripts;
                unsigned short num_sects;
                unsigned short num_specials;
                unsigned short num_textures;
                unsigned short num_lightmaps;
                bool vis_loaded;
                unsigned short num_lights;
                Header( const class Zone * zone );
                Header( istream & is );
                bool writeHeader( ostream & os ) const;
        };

        friend Zone::Header::Header( const class Zone * zone );

};

#endif

