2006-03-20 17:12:09 +00:00
|
|
|
/*
|
2014-06-01 17:55:23 +00:00
|
|
|
* Portions of this file are copyright Rebirth contributors and licensed as
|
|
|
|
* described in COPYING.txt.
|
|
|
|
* Portions of this file are copyright Parallax Software and licensed
|
|
|
|
* according to the Parallax license below.
|
|
|
|
* See COPYING.txt for license details.
|
|
|
|
|
2006-03-20 17:12:09 +00:00
|
|
|
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
|
|
|
|
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
|
|
|
|
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
|
|
|
|
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
|
|
|
|
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
|
|
|
|
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
|
|
|
|
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
|
|
|
|
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
|
|
|
|
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
|
|
|
|
COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Structure information for the player
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _PLAYER_H
|
|
|
|
#define _PLAYER_H
|
|
|
|
|
2013-07-14 03:10:18 +00:00
|
|
|
#include <physfs.h>
|
2006-03-20 17:12:09 +00:00
|
|
|
#include "vecmat.h"
|
2013-03-24 20:32:01 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_I) || defined(DXX_BUILD_DESCENT_II)
|
2006-03-20 17:12:09 +00:00
|
|
|
#include "weapon.h"
|
2013-03-24 20:32:01 +00:00
|
|
|
#endif
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2013-10-09 03:12:09 +00:00
|
|
|
#ifdef __cplusplus
|
2014-07-05 16:48:12 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cctype>
|
2014-06-21 23:55:24 +00:00
|
|
|
#include "pack.h"
|
2014-07-05 16:48:12 +00:00
|
|
|
#include "dxxsconf.h"
|
|
|
|
#include "compiler-array.h"
|
|
|
|
#include "compiler-static_assert.h"
|
2013-12-29 04:28:07 +00:00
|
|
|
#include "objnum.h"
|
2013-10-09 03:12:09 +00:00
|
|
|
|
2014-07-05 16:48:12 +00:00
|
|
|
#define MAX_PLAYERS 8u
|
2006-03-20 17:12:09 +00:00
|
|
|
#define MAX_MULTI_PLAYERS MAX_PLAYERS+3
|
|
|
|
|
|
|
|
// Initial player stat values
|
|
|
|
#define INITIAL_ENERGY i2f(100) // 100% energy to start
|
|
|
|
#define INITIAL_SHIELDS i2f(100) // 100% shields to start
|
|
|
|
|
|
|
|
#define MAX_ENERGY i2f(200) // go up to 200
|
|
|
|
#define MAX_SHIELDS i2f(200)
|
|
|
|
|
|
|
|
#define INITIAL_LIVES 3 // start off with 3 lives
|
|
|
|
|
|
|
|
// Values for special flags
|
|
|
|
#define PLAYER_FLAGS_INVULNERABLE 1 // Player is invincible
|
|
|
|
#define PLAYER_FLAGS_BLUE_KEY 2 // Player has blue key
|
|
|
|
#define PLAYER_FLAGS_RED_KEY 4 // Player has red key
|
|
|
|
#define PLAYER_FLAGS_GOLD_KEY 8 // Player has gold key
|
2013-03-03 01:03:33 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_II)
|
2006-03-20 17:12:09 +00:00
|
|
|
#define PLAYER_FLAGS_FLAG 16 // Player has his team's flag
|
2013-03-03 01:03:33 +00:00
|
|
|
#endif
|
2006-03-20 17:12:09 +00:00
|
|
|
#define PLAYER_FLAGS_MAP_ALL 64 // Player can see unvisited areas on map
|
2013-03-03 01:03:33 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_II)
|
2006-03-20 17:12:09 +00:00
|
|
|
#define PLAYER_FLAGS_AMMO_RACK 128 // Player has ammo rack
|
|
|
|
#define PLAYER_FLAGS_CONVERTER 256 // Player has energy->shield converter
|
2013-03-03 01:03:33 +00:00
|
|
|
#endif
|
2006-03-20 17:12:09 +00:00
|
|
|
#define PLAYER_FLAGS_QUAD_LASERS 1024 // Player shoots 4 at once
|
|
|
|
#define PLAYER_FLAGS_CLOAKED 2048 // Player is cloaked for awhile
|
2013-03-03 01:03:33 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_II)
|
2006-03-20 17:12:09 +00:00
|
|
|
#define PLAYER_FLAGS_AFTERBURNER 4096 // Player's afterburner is engaged
|
|
|
|
#define PLAYER_FLAGS_HEADLIGHT 8192 // Player has headlight boost
|
|
|
|
#define PLAYER_FLAGS_HEADLIGHT_ON 16384 // is headlight on or off?
|
|
|
|
|
|
|
|
#define AFTERBURNER_MAX_TIME (F1_0*5) // Max time afterburner can be on.
|
2013-03-03 01:03:33 +00:00
|
|
|
#endif
|
2006-03-20 17:12:09 +00:00
|
|
|
#define CALLSIGN_LEN 8 // so can use as filename (was: 12)
|
|
|
|
|
|
|
|
// Amount of time player is cloaked.
|
|
|
|
#define CLOAK_TIME_MAX (F1_0*30)
|
|
|
|
#define INVULNERABLE_TIME_MAX (F1_0*30)
|
|
|
|
|
2013-03-03 01:03:33 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_I)
|
|
|
|
#define PLAYER_STRUCT_VERSION 16 //increment this every time player struct changes
|
|
|
|
#elif defined(DXX_BUILD_DESCENT_II)
|
2006-03-20 17:12:09 +00:00
|
|
|
#define PLAYER_STRUCT_VERSION 17 // increment this every time player struct changes
|
|
|
|
|
|
|
|
// defines for teams
|
|
|
|
#define TEAM_BLUE 0
|
|
|
|
#define TEAM_RED 1
|
2013-03-03 01:03:33 +00:00
|
|
|
#endif
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2013-03-24 20:32:01 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_I) || defined(DXX_BUILD_DESCENT_II)
|
2014-07-05 16:48:12 +00:00
|
|
|
|
|
|
|
struct callsign_t
|
|
|
|
{
|
2014-12-07 00:53:15 +00:00
|
|
|
static const std::size_t array_length = CALLSIGN_LEN + 1;
|
2014-10-11 04:33:22 +00:00
|
|
|
operator const void *() const = delete;
|
2014-12-07 00:53:15 +00:00
|
|
|
typedef array<char, array_length> array_t;
|
|
|
|
typedef char elements_t[array_length];
|
2014-07-05 16:48:12 +00:00
|
|
|
array_t a;
|
|
|
|
static char lower_predicate(char c)
|
|
|
|
{
|
|
|
|
return std::tolower(static_cast<unsigned>(c));
|
|
|
|
}
|
|
|
|
callsign_t &zero_terminate(array_t::iterator i)
|
|
|
|
{
|
|
|
|
std::fill(i, end(a), 0);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
callsign_t ©(const char *s, std::size_t N)
|
|
|
|
{
|
|
|
|
return zero_terminate(std::copy_n(s, std::min(a.size() - 1, N), begin(a)));
|
|
|
|
}
|
|
|
|
callsign_t ©_lower(const char *s, std::size_t N)
|
|
|
|
{
|
|
|
|
return zero_terminate(std::transform(s, std::next(s, std::min(a.size() - 1, N)), begin(a), lower_predicate));
|
|
|
|
}
|
|
|
|
void lower()
|
|
|
|
{
|
|
|
|
auto ba = begin(a);
|
|
|
|
std::transform(ba, std::prev(end(a)), ba, lower_predicate);
|
|
|
|
a.back() = 0;
|
|
|
|
}
|
2014-12-07 00:53:15 +00:00
|
|
|
elements_t &buffer() __attribute_warn_unused_result
|
2014-07-05 16:48:12 +00:00
|
|
|
{
|
2014-12-07 00:53:15 +00:00
|
|
|
return *reinterpret_cast<elements_t *>(a.data());
|
2014-07-05 16:48:12 +00:00
|
|
|
}
|
|
|
|
template <std::size_t N>
|
|
|
|
callsign_t &operator=(const char (&s)[N])
|
|
|
|
{
|
2014-12-07 00:53:15 +00:00
|
|
|
static_assert(N <= array_length, "string too long");
|
2014-07-05 16:48:12 +00:00
|
|
|
return copy(s, N);
|
|
|
|
}
|
|
|
|
template <std::size_t N>
|
|
|
|
void copy_lower(const char (&s)[N])
|
|
|
|
{
|
2014-12-07 00:53:15 +00:00
|
|
|
static_assert(N <= array_length, "string too long");
|
2014-07-05 16:48:12 +00:00
|
|
|
return copy_lower(s, N);
|
|
|
|
}
|
|
|
|
void fill(char c) { a.fill(c); }
|
|
|
|
const char &operator[](std::size_t i) const
|
|
|
|
{
|
|
|
|
return a[i];
|
|
|
|
}
|
|
|
|
operator const char *() const
|
|
|
|
{
|
|
|
|
return &a[0];
|
|
|
|
};
|
2014-08-13 03:20:59 +00:00
|
|
|
bool operator==(const callsign_t &r) const
|
|
|
|
{
|
|
|
|
return a == r.a;
|
|
|
|
}
|
2014-10-11 04:33:22 +00:00
|
|
|
bool operator!=(const callsign_t &r) const
|
|
|
|
{
|
|
|
|
return !(*this == r);
|
|
|
|
}
|
2014-07-05 16:48:12 +00:00
|
|
|
};
|
|
|
|
static_assert(sizeof(callsign_t) == CALLSIGN_LEN + 1, "callsign_t too big");
|
|
|
|
|
2006-03-20 17:12:09 +00:00
|
|
|
// When this structure changes, increment the constant
|
|
|
|
// SAVE_FILE_VERSION in playsave.c
|
2014-06-21 23:55:24 +00:00
|
|
|
struct player : public prohibit_void_ptr<player>
|
2013-12-22 22:03:07 +00:00
|
|
|
{
|
2006-03-20 17:12:09 +00:00
|
|
|
// Who am I data
|
2014-07-05 16:48:12 +00:00
|
|
|
callsign_t callsign; // The callsign of this player, for net purposes.
|
2006-03-20 17:12:09 +00:00
|
|
|
sbyte connected; // Is the player connected or not?
|
2013-12-29 04:28:07 +00:00
|
|
|
objnum_t objnum; // What object number this player is. (made an int by mk because it's very often referenced)
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
// -- make sure you're 4 byte aligned now!
|
|
|
|
|
|
|
|
// Game data
|
|
|
|
uint flags; // Powerup flags, see below...
|
|
|
|
fix energy; // Amount of energy remaining.
|
|
|
|
fix shields; // shields remaining (protection)
|
|
|
|
ubyte lives; // Lives remaining, 0 = game over.
|
|
|
|
sbyte level; // Current level player is playing. (must be signed for secret levels)
|
|
|
|
ubyte laser_level; // Current level of the laser.
|
|
|
|
sbyte starting_level; // What level the player started on.
|
2013-12-29 04:28:07 +00:00
|
|
|
objnum_t killer_objnum; // Who killed me.... (-1 if no one)
|
2013-03-03 01:03:33 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_I)
|
|
|
|
ubyte primary_weapon_flags; // bit set indicates the player has this weapon.
|
|
|
|
ubyte secondary_weapon_flags; // bit set indicates the player has this weapon.
|
|
|
|
#elif defined(DXX_BUILD_DESCENT_II)
|
2006-03-20 17:12:09 +00:00
|
|
|
ushort primary_weapon_flags; // bit set indicates the player has this weapon.
|
|
|
|
ushort secondary_weapon_flags; // bit set indicates the player has this weapon.
|
2013-03-03 01:03:33 +00:00
|
|
|
#endif
|
2013-09-20 23:12:54 +00:00
|
|
|
ushort vulcan_ammo;
|
2006-03-20 17:12:09 +00:00
|
|
|
ushort secondary_ammo[MAX_SECONDARY_WEAPONS]; // How much ammo of each type.
|
|
|
|
|
|
|
|
// Statistics...
|
|
|
|
int last_score; // Score at beginning of current level.
|
|
|
|
int score; // Current score.
|
|
|
|
fix time_level; // Level time played
|
|
|
|
fix time_total; // Game time played (high word = seconds)
|
|
|
|
|
2010-12-22 00:17:59 +00:00
|
|
|
fix64 cloak_time; // Time cloaked
|
|
|
|
fix64 invulnerable_time; // Time invulnerable
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
short KillGoalCount; // Num of players killed this level
|
|
|
|
short net_killed_total; // Number of times killed total
|
|
|
|
short net_kills_total; // Number of net kills total
|
|
|
|
short num_kills_level; // Number of kills this level
|
|
|
|
short num_kills_total; // Number of kills total
|
|
|
|
short num_robots_level; // Number of initial robots this level
|
|
|
|
short num_robots_total; // Number of robots total
|
|
|
|
ushort hostages_rescued_total; // Total number of hostages rescued.
|
|
|
|
ushort hostages_total; // Total number of hostages.
|
|
|
|
ubyte hostages_on_board; // Number of hostages on ship.
|
|
|
|
ubyte hostages_level; // Number of hostages on this level.
|
|
|
|
fix homing_object_dist; // Distance of nearest homing object.
|
|
|
|
sbyte hours_level; // Hours played (since time_total can only go up to 9 hours)
|
|
|
|
sbyte hours_total; // Hours played (since time_total can only go up to 9 hours)
|
2014-01-11 21:51:29 +00:00
|
|
|
};
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2010-12-22 00:17:59 +00:00
|
|
|
// Same as above but structure how Savegames expect
|
2013-12-22 22:03:07 +00:00
|
|
|
struct player_rw
|
|
|
|
{
|
2006-03-20 17:12:09 +00:00
|
|
|
// Who am I data
|
2014-07-05 16:48:12 +00:00
|
|
|
callsign_t callsign; // The callsign of this player, for net purposes.
|
2006-03-20 17:12:09 +00:00
|
|
|
ubyte net_address[6]; // The network address of the player.
|
|
|
|
sbyte connected; // Is the player connected or not?
|
|
|
|
int objnum; // What object number this player is. (made an int by mk because it's very often referenced)
|
|
|
|
int n_packets_got; // How many packets we got from them
|
|
|
|
int n_packets_sent; // How many packets we sent to them
|
|
|
|
|
|
|
|
// -- make sure you're 4 byte aligned now!
|
|
|
|
|
|
|
|
// Game data
|
|
|
|
uint flags; // Powerup flags, see below...
|
|
|
|
fix energy; // Amount of energy remaining.
|
|
|
|
fix shields; // shields remaining (protection)
|
|
|
|
ubyte lives; // Lives remaining, 0 = game over.
|
|
|
|
sbyte level; // Current level player is playing. (must be signed for secret levels)
|
|
|
|
ubyte laser_level; // Current level of the laser.
|
|
|
|
sbyte starting_level; // What level the player started on.
|
|
|
|
short killer_objnum; // Who killed me.... (-1 if no one)
|
2013-03-03 01:03:33 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_I)
|
|
|
|
ubyte primary_weapon_flags; // bit set indicates the player has this weapon.
|
|
|
|
ubyte secondary_weapon_flags; // bit set indicates the player has this weapon.
|
|
|
|
#elif defined(DXX_BUILD_DESCENT_II)
|
2010-12-22 00:17:59 +00:00
|
|
|
ushort primary_weapon_flags; // bit set indicates the player has this weapon.
|
|
|
|
ushort secondary_weapon_flags; // bit set indicates the player has this weapon.
|
2013-03-03 01:03:33 +00:00
|
|
|
#endif
|
2013-09-21 17:36:20 +00:00
|
|
|
ushort laser_ammo;
|
2013-09-20 23:12:54 +00:00
|
|
|
ushort vulcan_ammo;
|
|
|
|
ushort spreadfire_ammo, plasma_ammo, fusion_ammo;
|
2013-09-21 17:36:20 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_II)
|
|
|
|
ushort obsolete_primary_ammo[MAX_PRIMARY_WEAPONS - 5];
|
2013-09-20 23:12:54 +00:00
|
|
|
#endif
|
2010-12-22 00:17:59 +00:00
|
|
|
ushort secondary_ammo[MAX_SECONDARY_WEAPONS]; // How much ammo of each type.
|
|
|
|
|
2013-03-03 01:03:33 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_II)
|
2010-12-22 00:17:59 +00:00
|
|
|
ushort pad; // Pad because increased weapon_flags from byte to short -YW 3/22/95
|
2013-03-03 01:03:33 +00:00
|
|
|
#endif
|
2006-03-20 17:12:09 +00:00
|
|
|
// -- make sure you're 4 byte aligned now
|
|
|
|
|
|
|
|
// Statistics...
|
|
|
|
int last_score; // Score at beginning of current level.
|
|
|
|
int score; // Current score.
|
|
|
|
fix time_level; // Level time played
|
|
|
|
fix time_total; // Game time played (high word = seconds)
|
|
|
|
|
|
|
|
fix cloak_time; // Time cloaked
|
|
|
|
fix invulnerable_time; // Time invulnerable
|
|
|
|
|
2013-03-03 01:03:33 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_II)
|
2010-12-22 00:17:59 +00:00
|
|
|
short KillGoalCount; // Num of players killed this level
|
2013-03-03 01:03:33 +00:00
|
|
|
#endif
|
2006-03-20 17:12:09 +00:00
|
|
|
short net_killed_total; // Number of times killed total
|
|
|
|
short net_kills_total; // Number of net kills total
|
|
|
|
short num_kills_level; // Number of kills this level
|
|
|
|
short num_kills_total; // Number of kills total
|
|
|
|
short num_robots_level; // Number of initial robots this level
|
|
|
|
short num_robots_total; // Number of robots total
|
|
|
|
ushort hostages_rescued_total; // Total number of hostages rescued.
|
|
|
|
ushort hostages_total; // Total number of hostages.
|
|
|
|
ubyte hostages_on_board; // Number of hostages on ship.
|
|
|
|
ubyte hostages_level; // Number of hostages on this level.
|
|
|
|
fix homing_object_dist; // Distance of nearest homing object.
|
|
|
|
sbyte hours_level; // Hours played (since time_total can only go up to 9 hours)
|
|
|
|
sbyte hours_total; // Hours played (since time_total can only go up to 9 hours)
|
2013-12-22 22:03:07 +00:00
|
|
|
} __pack__;
|
2013-09-21 17:36:20 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_I)
|
|
|
|
typedef char player_rw_padding_check[sizeof(player_rw) == 116 ? 1 : -1];
|
|
|
|
#elif defined(DXX_BUILD_DESCENT_II)
|
|
|
|
typedef char player_rw_padding_check[sizeof(player_rw) == 142 ? 1 : -1];
|
|
|
|
#endif
|
2013-03-24 20:32:01 +00:00
|
|
|
#endif
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2010-12-22 00:17:59 +00:00
|
|
|
#define N_PLAYER_GUNS 8
|
2012-03-28 10:26:24 +00:00
|
|
|
#define N_PLAYER_SHIP_TEXTURES 32
|
2010-12-22 00:17:59 +00:00
|
|
|
|
2013-12-22 22:03:07 +00:00
|
|
|
struct player_ship
|
|
|
|
{
|
2010-12-22 00:17:59 +00:00
|
|
|
int model_num;
|
|
|
|
int expl_vclip_num;
|
|
|
|
fix mass,drag;
|
|
|
|
fix max_thrust,reverse_thrust,brakes; //low_thrust
|
|
|
|
fix wiggle;
|
|
|
|
fix max_rotthrust;
|
|
|
|
vms_vector gun_points[N_PLAYER_GUNS];
|
2013-03-03 01:03:33 +00:00
|
|
|
}
|
|
|
|
#if defined(DXX_BUILD_DESCENT_I)
|
|
|
|
__pack__
|
|
|
|
#endif
|
2013-12-22 22:03:07 +00:00
|
|
|
;
|
2010-12-22 00:17:59 +00:00
|
|
|
|
2014-09-21 22:10:12 +00:00
|
|
|
typedef unsigned playernum_t;
|
|
|
|
typedef array<playernum_t, MAX_PLAYERS> playernum_array_t;
|
|
|
|
|
2014-09-20 23:47:27 +00:00
|
|
|
extern unsigned N_players; // Number of players ( >1 means a net game, eh?)
|
2014-09-21 22:10:12 +00:00
|
|
|
extern playernum_t Player_num; // The player number who is on the console.
|
2010-12-22 00:17:59 +00:00
|
|
|
|
2013-03-03 01:03:33 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_I)
|
|
|
|
#define DXX_PLAYER_HEADER_ADD_EXTRA_PLAYERS 0
|
|
|
|
#elif defined(DXX_BUILD_DESCENT_II)
|
|
|
|
#define DXX_PLAYER_HEADER_ADD_EXTRA_PLAYERS 4
|
|
|
|
#endif
|
|
|
|
#if defined(DXX_BUILD_DESCENT_I) || defined(DXX_BUILD_DESCENT_II)
|
2014-08-08 03:02:59 +00:00
|
|
|
extern array<player, MAX_PLAYERS + DXX_PLAYER_HEADER_ADD_EXTRA_PLAYERS> Players; // Misc player info
|
2013-03-24 20:32:01 +00:00
|
|
|
void player_rw_swap(player_rw *p, int swap);
|
2013-03-03 01:03:33 +00:00
|
|
|
#endif
|
2009-10-05 02:51:37 +00:00
|
|
|
|
2012-11-11 00:12:17 +00:00
|
|
|
extern struct object *Guided_missile[MAX_PLAYERS];
|
|
|
|
extern int Guided_missile_sig[MAX_PLAYERS];
|
|
|
|
|
2006-03-20 17:12:09 +00:00
|
|
|
/*
|
2011-06-01 07:59:55 +00:00
|
|
|
* reads a player_ship structure from a PHYSFS_file
|
2006-03-20 17:12:09 +00:00
|
|
|
*/
|
2011-06-01 07:59:55 +00:00
|
|
|
void player_ship_read(player_ship *ps, PHYSFS_file *fp);
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2013-10-09 03:12:09 +00:00
|
|
|
#endif
|
|
|
|
|
2006-03-20 17:12:09 +00:00
|
|
|
#endif
|