/* Danger from the Deep - Open source submarine simulation Copyright (C) 2003-2006 Thorsten Jordan, Luis Barrancos and others. 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 */ // game // subsim (C)+(W) Thorsten Jordan. SEE LICENSE #ifndef GAME_H #define GAME_H #define PINGREMAINTIME 1.0 // seconds #define PINGANGLE 15 // angle #define PINGLENGTH 1000 // meters. for drawing #define ASDICRANGE 1500.0 // meters fixme: historic values? #define MAX_ACUSTIC_CONTACTS 5 // max. nr of simultaneous trackable acustic contacts #include #include // use forward declarations to avoid unneccessary compile dependencies class ship; class submarine; class airplane; class torpedo; class depth_charge; class gun_shell; class model; class global_data; class sea_object; class network_connection; class water_splash; class particle; class convoy; #include "angle.h" #include "date.h" #include "vector2.h" #include "vector3.h" #include "color.h" #include "logbook.h" #include "ptrset.h" #include "xml.h" #include "sensors.h" #include "sonar.h" #include "event.h" #include "ptrlist.h" // Note! do NOT include user_interface here, class game MUST NOT call any method // of class user_interface or its heirs. // network messages #define MSG_length 16 #define MSG_cancel "DFTD-cancel! " #define MSG_ask "DFTD-ask? " #define MSG_offer "DFTD-offer! " #define MSG_join "DFTD-join? " #define MSG_joined "DFTD-joined! " #define MSG_initgame "DFTD-init! " #define MSG_ready "DFTD-ready! " #define MSG_start "DFTD-start! " #define MSG_gamestate "DFTD-gamestate: " #define MSG_command "DFTD-command: " ///\brief Central object of the game world with physics simulation etc. class game { public: // fixme: may be redundant with event_ping ! struct ping { vector2 pos; angle dir; double time; double range; angle ping_angle; ping(const vector2& p, angle d, double t, double range, const angle& ping_angle_ ) : pos(p), dir(d), time(t), range ( range ), ping_angle ( ping_angle_ ) {} ~ping() {} ping(const xml_elem& parent); void save(xml_elem& parent) const; }; struct sink_record { date dat; std::string descr; // fixme: store type, use a static ship function to retrieve a matching description, via specfilename! std::string mdlname; // model file name string std::string specfilename; // spec file name (base model name) std::string layoutname; // model skin unsigned tons; sink_record(date d, const std::string& s, const std::string& m, const std::string& sn, const std::string& ln, unsigned t) : dat(d), descr(s), mdlname(m), specfilename(sn), layoutname(ln), tons(t) {} sink_record(const xml_elem& parent); void save(xml_elem& parent) const; }; struct job { job() {} virtual void run() = 0; virtual double get_period() const = 0; virtual ~job() {} }; // in which state is the game // normal mode (running), or stop on next cycle (reason given by value) enum run_state { running, player_killed, mission_complete, contact_lost }; // time between records of trail positions static const double TRAIL_TIME; protected: // begin [SAVE] ptrset ships; ptrset submarines; ptrset airplanes; ptrset torpedoes; ptrset depth_charges; ptrset gun_shells; ptrset water_splashes; ptrset convoys; ptrset particles; // end [SAVE] run_state my_run_state; ptrlist events; std::list > jobs; // generated by interface construction, no gameplay data // the player (note that playing is not limited to submarines!) sea_object* player; // [SAVE] std::list sunken_ships; // [SAVE] logbook players_logbook; // [SAVE] double time; // global time (in seconds since 1.1.1939, 0:0 hrs) (universal time!) [SAVE] double last_trail_time; // for position trail recording [SAVE] date equipment_date; // date that equipment was created. used for torpedo loading enum weathers { sunny, clouded, raining, storm };//fixme double max_view_dist; // maximum visibility according to weather conditions, fixme recomputed or save? std::list pings; // [SAVE] // network game type (0 = single player, 1 = server, 2 = client) unsigned networktype; // [SAVE] later! // the connection to the server (zero if this is the server) network_connection* servercon; // [SAVE] later! // the connections to the clients (at least one if this is the server, else empty) std::vector clientcons; // [SAVE] later! // time in milliseconds that game is paused between simulation steps. // for small pauses to compensate long image loading times unsigned freezetime, freezetime_start; game(); game& operator= (const game& other); game(const game& other); public: // create new custom mission // expects: size small,medium,large, escort size none,small,medium,large, // time of day [0,4) night,dawn,day,dusk game(const std::string& subtype, unsigned cvsize, unsigned cvesc, unsigned timeofday, unsigned timeperiod, unsigned nr_of_players = 1); // create from mission file or savegame (xml file) game(const std::string& filename); virtual ~game(); virtual void save(const std::string& savefilename, const std::string& description) const; static std::string read_description_of_savegame(const std::string& filename); void compute_max_view_dist(); // fixme - public? virtual void simulate(double delta_t); const std::list& get_sunken_ships() const { return sunken_ships; }; const logbook& get_players_logbook() const { return players_logbook; } void add_logbook_entry(const std::string& s); double get_time() const { return time; }; date get_date() const { return date(unsigned(time)); }; date get_equipment_date() const { return equipment_date; } double get_max_view_distance() const { return max_view_dist; } /** This method is needed to verify for day and night mode for the display methods within the user interfaces. @return true when day mode, false when night mode */ bool is_day_mode () const; /** This method calculates a depth depending factor. A deep diving submarine is harder to detect with ASDIC than a submarine at periscope depth. @param sub location vector of submarine @return depth factor */ virtual double get_depth_factor ( const vector3& sub ) const; sea_object* get_player() const { return player; } double get_last_trail_record_time() const { return last_trail_time; } // compute visibility data //fixme: remove the single functions, they're always called together //by visible_sea/visible_surface objects //they all map to the same function. //if certain objects should not be reported, unmask them with extra-parameter. virtual std::vector visible_ships(const sea_object* o) const; virtual std::vector visible_submarines(const sea_object* o) const; virtual std::vector visible_airplanes(const sea_object* o) const; virtual std::vector visible_torpedoes(const sea_object* o) const; virtual std::vector visible_depth_charges(const sea_object* o) const; virtual std::vector visible_gun_shells(const sea_object* o) const; virtual std::vector visible_water_splashes(const sea_object* o) const; virtual std::vector visible_particles (const sea_object* o ) const; // computes visible ships, submarines (surfaced) and airplanes virtual std::vector visible_surface_objects(const sea_object* o) const; // computes ships, subs (surfaced), airplanes, torpedoes. But not fast moving objects // like shells/DCs, because they need to be detected more often, and this function // is called once per second normally. virtual std::vector visible_sea_objects(const sea_object* o) const; // fixme: maybe we should distuingish between passivly and activly detected objects... // passivly detected objects should store their noise source as position and not their // geometric center position! virtual std::vector sonar_ships(const sea_object* o) const; virtual std::vector sonar_submarines(const sea_object* o) const; virtual std::vector sonar_sea_objects(const sea_object* o) const; // fixme: return sonar_contact here (when the noise_pos fix is done...) virtual ship* sonar_acoustical_torpedo_target(const torpedo* o) const; // std::list<*> radardetected_ships(...); // later! virtual std::vector radar_submarines(const sea_object* o) const; virtual std::vector radar_ships(const sea_object* o) const; //virtual std::vector radar_airplanes(const sea_object* o) const; virtual std::vector radar_sea_objects(const sea_object* o) const; ///\brief compute sound strengths caused by all ships /** @param listener object that listens via passive sonar @passive listening_direction direction for listening @return absolute freq. strength in dB and noise struct of received noise frequencies (in dB) */ std::pair sonar_listen_ships(const ship* listener, angle listening_direction) const; // append objects to vector template static void append_vec(std::vector& vec, const std::vector& vec2) { for (unsigned i = 0; i < vec2.size(); ++i) vec.push_back(vec2[i]); } std::vector convoy_positions() const; // fixme // create new objects void spawn_ship(ship* s); void spawn_submarine(submarine* u); void spawn_airplane(airplane* a); void spawn_torpedo(torpedo* t); void spawn_gun_shell(gun_shell* s, const double &calibre); void spawn_depth_charge(depth_charge* dc); void spawn_water_splash(water_splash* ws); void spawn_convoy(convoy* cv); void spawn_particle(particle* pt); // simulation events void dc_explosion(const depth_charge& dc); // depth charge exploding bool gs_impact(const gun_shell *gs); // gun shell impact void torp_explode(const torpedo *t); // torpedo explosion/impact void ship_sunk( const ship* s ); // a ship sinks // simulation actions, fixme send something over net for them, fixme : maybe vector not list? virtual void ping_ASDIC(std::list& contacts, sea_object* d, const bool& move_sensor, const angle& dir = angle ( 0.0f ) ); // various functions (fixme: sort, cleanup) void register_job(job* j); // insert/remove job in job list void unregister_job(job* j); const std::list& get_pings() const { return pings; }; // fixme: maybe vector not list template ship* check_units ( torpedo* t, const ptrset& units ); // fixme why is this not const? if it changes game, it must be send over network, and // then it can't be a function! bool check_torpedo_hit(torpedo* t, bool runlengthfailure, bool failure); // dito, see check_torpedo_hit-comment sea_object* contact_in_direction(const sea_object* o, const angle& direction); ship* ship_in_direction_from_pos(const sea_object* o, const angle& direction); submarine* sub_in_direction_from_pos(const sea_object* o, const angle& direction); const torpedo* get_torpedo_for_camera_track(unsigned nr) const; bool is_collision(const sea_object* s1, const sea_object* s2) const; bool is_collision(const sea_object* s, const vector2& pos) const; double water_depth(const vector2& pos) const; // is editor? virtual bool is_editor() const { return false; } // sun/moon and light color/brightness double compute_light_brightness(const vector3& viewpos, vector3& sundir) const; // depends on sun/moon colorf compute_light_color(const vector3& viewpos) const; // depends on sun/moon vector3 compute_sun_pos(const vector3& viewpos) const; vector3 compute_moon_pos(const vector3& viewpos) const; // Translate pointers to numbers and vice versa. Used for load/save sea_object* load_ptr(unsigned nr) const; ship* load_ship_ptr(unsigned nr) const; convoy* load_convoy_ptr(unsigned nr) const; unsigned save_ptr(const sea_object* s) const; unsigned save_ptr(const convoy* c) const; void freeze_time(); void unfreeze_time(); void add_event(event* e) { events.push_back(e); } const ptrlist& get_events() const { return events; } run_state get_run_state() const { return my_run_state; } unsigned get_freezetime() const { return freezetime; } unsigned get_freezetime_start() const { return freezetime_start; } unsigned process_freezetime() { unsigned f = freezetime; freezetime = 0; return f; } }; #endif