20 #define VS_PI 3.1415926535897931
24 string hashname = unitname+
"__"+
faction;
27 if ( (*i)->RowExists( hashname, where ) )
29 else if ( (*i)->RowExists( unitname, where ) )
36 extern void pushMesh( std::vector< Mesh* >&mesh,
37 float &randomstartframe,
38 float &randomstartseconds,
44 double texturestarttime );
50 string::size_type when;
51 string::size_type ofs = 0;
52 while ( ( when = upgrades.find(
'{', ofs ) ) != string::npos ) {
53 string::size_type where = upgrades.find(
'}', when+1 );
54 string upgrade = upgrades.substr( when+1, ( (where == string::npos) ? string::npos : where-when-1 ) );
55 ofs = ( (where == string::npos) ? string::npos : where+1 );
57 unsigned int mountoffset = 0;
58 unsigned int subunitoffset = 0;
59 string::size_type where1 = upgrade.find(
';' );
60 string::size_type where2 = upgrade.rfind(
';' );
61 if (where1 != string::npos) {
62 mountoffset =
XMLSupport::parse_int( upgrade.substr( where1+1, where2 != where1 ? where2 : upgrade.length() ) );
63 if (where2 != where1 && where2 != string::npos)
66 upgrade = upgrade.substr( 0, where1 );
67 if (upgrade.length() == 0)
77 un->Unit::Upgrade( upgradee,
85 float &randomstartframe,
86 float &randomstartseconds,
88 const std::string &meshes,
91 vector< unsigned int > *
counts )
93 string::size_type where, when, wheresf, wherest, ofs = 0;
94 if (counts) counts->clear();
97 while ( ( ofs = meshes.find(
'{', ofs ) ) != string::npos )
99 if (counts) counts->reserve( nelem );
100 xmeshes.reserve( nelem );
103 while ( ( where = meshes.find(
'{', ofs ) ) != string::npos ) {
104 when = meshes.find(
'}', where+1 );
105 string mesh = meshes.substr( where+1, ( (when == string::npos) ? string::npos : when-where-1 ) );
106 ofs = ( (when == string::npos) ? string::npos : when+1 );
108 wheresf = mesh.find(
';' );
111 if (wheresf != string::npos) {
112 startf = mesh.substr( wheresf+1 );
113 mesh = mesh.substr( 0, wheresf );
114 wherest = startf.find(
';' );
115 if (wherest != string::npos) {
116 startt = startf.substr( wherest+1 );
117 startf = startf.substr( 0, wherest );
120 int startframe = startf ==
"RANDOM" ? -1 : ( startf ==
"ASYNC" ? -1 : atoi( startf.c_str() ) );
121 float starttime = startt ==
"RANDOM" ? -1.0f : atof( startt.c_str() );
122 unsigned int s = xmeshes.size();
123 pushMesh( xmeshes, randomstartframe, randomstartseconds, mesh.c_str(), unitscale,
faction, fg, startframe, starttime );
124 if (counts) counts->push_back( xmeshes.size()-s );
128 static std::pair< string::size_type, string::size_type >
nextElementRange(
const string &inp,
129 string::size_type &
start,
130 string::size_type end )
132 string::size_type ostart =
start;
133 start = inp.find(
';', start );
134 if ( start != string::npos && ( start != end && (end == string::npos || start < end) ) ) {
136 return std::pair< string::size_type, string::size_type > ( ostart, start-1 );
139 return std::pair< string::size_type, string::size_type > ( ostart, end );
145 std::pair< string::size_type, string::size_type >rng =
nextElementRange( inp, start, end );
146 if (rng.second == string::npos)
147 return inp.substr( rng.first );
150 return inp.substr( rng.first, rng.second-rng.first );
153 static int nextElementInt(
const string &inp, string::size_type &
start, string::size_type end,
int def = 0 )
155 std::pair< string::size_type, string::size_type >rng =
nextElementRange( inp, start, end );
156 return (rng.first == rng.second) ? def : atoi( inp.c_str()+rng.first );
159 static double nextElementFloat(
const string &inp, string::size_type &
start, string::size_type end,
double def = 0 )
161 std::pair< string::size_type, string::size_type >rng =
nextElementRange( inp, start, end );
162 return (rng.first == rng.second) ? def : atof( inp.c_str()+rng.first );
165 static double nextElementBool(
const string &inp, string::size_type &
start, string::size_type end,
bool def =
false )
167 std::pair< string::size_type, string::size_type >rng =
nextElementRange( inp, start, end );
171 == string::npos) ? string::npos : (rng.second
177 string::size_type
start = 0;
178 std::pair< string::size_type, string::size_type >rng =
nextElementRange( inp, start, string::npos );
179 string ret = inp.substr( rng.first, ( (rng.second == string::npos) ? string::npos : (rng.second-rng.first) ) );
180 inp.erase( 0, ( (rng.second == string::npos) ? string::npos : (rng.second+1) ) );
184 static bool stob(
const string &inp,
bool defaul )
186 if (inp.length() != 0)
191 static double stof(
const string &inp,
double def = 0 )
193 if (inp.length() != 0)
198 static int stoi(
const string &inp,
int def = 0 )
200 if (inp.length() != 0)
211 string::size_type where, when, ofs = 0;
212 unsigned int first_new_mount = thus->
mounts.size();
215 while ( ( ofs = mounts.find(
'{', ofs ) ) != string::npos )
220 while ( ( where = mounts.find(
'{', ofs ) ) != string::npos ) {
221 if ( ( when = mounts.find(
'}', where+1 ) ) != string::npos ) {
222 string::size_type elemstart = where+1, elemend = when;
249 if ( fabs( Q.i ) == fabs( R.i ) && fabs( Q.j ) == fabs( R.j ) && fabs( Q.k ) == fabs( R.k ) ) {
256 CrossProduct( Q, R, P );
257 CrossProduct( R, P, Q );
263 if ( mountsize.length() ) {
269 thus->
mounts.push_back( mnt );
270 }
else {ofs = string::npos; }}
271 unsigned char parity = 0;
272 for (
unsigned int a = first_new_mount;
a < thus->
mounts.size(); ++
a) {
274 if ( (
a&1) == parity ) {
289 printf(
"Sound error\n" );
310 static vector< SubUnitStruct >
GetSubUnits(
const std::string &subunits )
312 string::size_type where, when, ofs = 0;
313 vector< SubUnitStruct >ret;
316 while ( ( ofs = subunits.find(
'{', ofs ) ) != string::npos )
318 ret.reserve( nelem );
321 while ( ( where = subunits.find(
'{', ofs ) ) != string::npos ) {
322 if ( ( when = subunits.find(
'}', ofs ) ) != string::npos ) {
323 string::size_type elemstart = where+1, elemend = when;
340 ret.push_back(
SubUnitStruct( filename, pos, Q, R, restricted ) );
356 vector< SubUnitStruct >su =
GetSubUnits( subunits );
357 xml.
units.reserve( subunits.size()+xml.
units.size() );
358 for (vector< SubUnitStruct >::iterator
i = su.begin();
i != su.end(); ++
i) {
359 string filename = (*i).filename;
363 double restricted = (*i).restricted;
365 if (xml.
units.back()->name ==
"LOAD_FAILED") {
366 xml.
units.back()->limits.yaw = 0;
367 xml.
units.back()->limits.pitch = 0;
368 xml.
units.back()->limits.roll = 0;
369 xml.
units.back()->limits.lateral = xml.
units.back()->limits.retro = xml.
units.back()->limits.forward =
370 xml.
units.back()->limits.afterburn = 0.0;
373 xml.
units.back()->SetRecursiveOwner( thus );
374 xml.
units.back()->SetOrientation( Q, R );
376 xml.
units.back()->prev_physical_state = xml.
units.back()->curr_physical_state;
378 xml.
units.back()->limits.structurelimits = R.Cast();
379 xml.
units.back()->limits.limitmin = restricted;
380 xml.
units.back()->name = filename;
381 if (xml.
units.back()->pImage->unitwriter != NULL)
382 xml.
units.back()->pImage->unitwriter->setName( filename );
385 for (
int a = xml.
units.size()-1;
a >= 0;
a--) {
386 bool randomspawn = xml.
units[
a]->name.get().find(
"randomspawn" ) != string::npos;
389 if (chancetospawn > rand()%100)
402 string::size_type where, when;
403 string::size_type ofs = 0;
410 while ( ( ofs = docks.find(
'{', ofs ) ) != string::npos )
415 while ( ( where = docks.find(
'{', ofs ) ) != string::npos ) {
416 if ( ( when = docks.find(
'}', where+1 ) ) != string::npos ) {
417 string::size_type elemstart = where+1, elemend = when;
427 for (
int i = 0;
i < overlap;
i++)
438 static float default_halo_activation =
440 string::size_type where, when;
441 string::size_type ofs = 0;
442 while ( ( where = lights.find(
'{', ofs ) ) != string::npos ) {
443 if ( ( when = lights.find(
'}', where+1 ) ) != string::npos ) {
444 string::size_type elemstart = where+1, elemend = when;
454 scale.j = scale.k = scale.i;
459 double act_speed =
nextElementFloat( lights, elemstart, elemend, default_halo_activation );
461 thus->
addHalo( filename.c_str(), pos*xml.
unitscale, scale.Cast(), halocolor,
"", act_speed );
473 string::size_type where, when, ofs = 0;
476 while ( ( ofs = imports.find(
'{', ofs ) ) != string::npos )
481 while ( ( where = imports.find(
'{', ofs ) ) != string::npos ) {
482 if ( ( when = imports.find(
'}', where+1 ) ) != string::npos ) {
483 string::size_type elemstart = where+1, elemend = when;
492 thus->
ImportPartList( filename, price, pricestddev, quant, quantstddev );
501 string::size_type where, when, ofs = 0;
504 while ( ( ofs = cargos.find(
'{', ofs ) ) != string::npos )
509 while ( ( where = cargos.find(
'{', ofs ) ) != string::npos ) {
510 if ( ( when = cargos.find(
'}', where+1 ) ) != string::npos ) {
512 string::size_type elemstart = where+1, elemend = when;
526 carg.
category.get().find(
"upgrades/") == 0 );
538 string::size_type elemstart = 0, elemend = string::npos;
539 for (
int i = 0; i < 1+MAXVDUS+UnitImages< void >::NUMGAUGES; ++
i)
547 const string semi =
";";
549 for (
int i = 0; i < 1+MAXVDUS+UnitImages< void >::NUMGAUGES; ++
i) {
560 const string semi =
";";
563 for (
int i = numg;
i < 2*numg; ++
i) {
573 if (sounds.length() != 0) {
628 string::size_type elemstart = 0, elemend = string::npos;
635 static int AssignIf(
const string &inp,
float &val,
float &val1,
float &val2 )
637 if ( inp.length() ) {
648 if ( inp.length() ) {
658 return fuel_conversion;
663 #define LOADROW_OPTIMIZER ((0x348299ab))
666 #define FORCE_OPTIMIZER (1)
668 #define OPTIMIZER_INDEX( Variable ) OPTIDX_##Variable
670 #define INIT_OPTIMIZER( keys, Variable ) do{OPTIMIZER_INDEX(Variable)=(keys.push_back(#Variable),(keys.size()-1));}while(0)
672 #define DEF_OPTIMIZER( Variable ) static unsigned int OPTIMIZER_INDEX( Variable ) = CSVTable::optimizer_undefined;
676 #define OPTIM_GET( row, table, variable ) \
678 (table->optimizer_indexes[OPTIMIZER_INDEX(variable)] == CSVTable::optimizer_undefined) \
680 : row[ table->optimizer_indexes[OPTIMIZER_INDEX(variable)] ] \
685 #define OPTIM_GET( row, table, variable ) \
690 (OPTIMIZER_INDEX(variable) == CSVTable::optimizer_undefined) \
692 table->optimizer_indexes[OPTIMIZER_INDEX(variable)] \
693 == CSVTable::optimizer_undefined \
697 : row[table->optimizer_indexes[OPTIMIZER_INDEX(variable )]] \
839 static std::vector< std::string >keys;
840 static bool optimizer_keys_init =
false;
841 if (!optimizer_keys_init) {
842 optimizer_keys_init =
true;
843 printf(
"Initializing optimizer\n" );
966 if ( ( tmpstr =
OPTIM_GET( row, table, Hud_image ) ).length() != 0 ) {
976 if ( ( tmpstr =
OPTIM_GET( row, table, FaceCamera ) ).length() != 0 )
978 std::string llegacy_combat_role(
OPTIM_GET( row, table, Combat_Role ) );
979 std::string lunit_role(
OPTIM_GET( row, table, Unit_Role ) );
980 std::string lattack_preference(
OPTIM_GET( row, table, Attack_Preference ) );
981 if (lunit_role.length() == 0)
985 if (lattack_preference.length() == 0)
1033 int shieldcount = 0;
1037 memset( &two, 0,
sizeof (
Shield) );
1038 memset( &four, 0,
sizeof (
Shield) );
1039 memset( &eight, 0,
sizeof (
Shield) );
1066 eight.
shield8.frontleftbottommax = eight.
shield8.frontleftbottom;
1067 eight.
shield8.frontrightbottommax = eight.
shield8.frontrightbottom;
1068 eight.
shield8.backrightbottommax = eight.
shield8.backrightbottom;
1070 float r45 =
VS_PI/4;
1071 float r90 =
VS_PI/2;
1072 float r135 = 3*
VS_PI/4;
1074 float r225 = 5*
VS_PI/4;
1075 float r270 = 3*
VS_PI/2;
1076 float r315 = 7*
VS_PI/4;
1077 float r360 = 2*
VS_PI;
1082 if (shieldcount == 8) {
1131 }
else if (shieldcount == 4) {
1157 }
else if (shieldcount == 2) {
1175 for (iter = 0; iter < shieldcount; ++iter) {
1211 std::string t, tn, tp;
1212 t =
OPTIM_GET( row, table, Yaw_Governor );
1213 tn =
OPTIM_GET( row, table, Yaw_Governor_Right );
1214 tp =
OPTIM_GET( row, table, Yaw_Governor_Left );
1217 t =
OPTIM_GET( row, table, Pitch_Governor );
1218 tn =
OPTIM_GET( row, table, Pitch_Governor_Up );
1219 tp =
OPTIM_GET( row, table, Pitch_Governor_Down );
1222 t =
OPTIM_GET( row, table, Roll_Governor );
1223 tn =
OPTIM_GET( row, table, Roll_Governor_Right );
1224 tp =
OPTIM_GET( row, table, Roll_Governor_Left );
1235 Left_Accel ) )+
::stof(
OPTIM_GET( row, table, Right_Accel ) ) )*game_accel*game_speed;
1238 Top_Accel ) )+
::stof(
OPTIM_GET( row, table, Bottom_Accel ) ) )*game_accel*game_speed;
1249 std::string iffval =
OPTIM_GET( row, table, Radar_Color );
1250 if ((iffval.empty()) || (iffval ==
"FALSE") || (iffval ==
"0"))
1254 else if ((iffval ==
"TRUE") || (iffval ==
"1"))
1260 else if (iffval ==
"THREAT")
1267 else if (iffval ==
"BUBBLE_THREAT")
1275 else if (iffval ==
"PLANE")
1281 else if (iffval ==
"PLANE_THREAT")
1291 unsigned int value =
stoi(iffval, 0);
1342 std::string tractorability =
OPTIM_GET( row, table, Tractorability );
1343 unsigned char tflags;
1344 if ( !tractorability.empty() ) {
1346 if (tractorability.find_first_of(
"pP" ) != string::npos)
1348 if (tractorability.find_first_of(
"iI" ) != string::npos)
1356 static std::string expani =
vs_config->
getVariable(
"graphics",
"explosion_animation",
"explosion_orange.ani" );
1366 static std::string shieldtex =
vs_config->
getVariable(
"graphics",
"shield_texture",
"shield.bmp" );
1367 static std::string shieldtechnique =
vs_config->
getVariable(
"graphics",
"shield_technique",
"" );
1370 meshdata.back()->EnableSpecialFX();
1374 vector< mesh_polygon >polies;
1381 string tmpname = row[0];
1385 if ( ( val =
OPTIM_GET( row, table, Use_Rapid ) ).length() )
1389 meshdata.back()->GetPolys( polies );
1413 unsigned int which = 1<<
i;
1432 for (
int i = ( (
int)
unitTables.size() )-(readlast ? 1 : 2);
i >= 0; --
i) {
1434 if (
unitTables[
i]->RowExists( hashname, where ) ) {
1437 }
else if (
unitTables[
i]->RowExists( filename, where ) ) {
1451 if (!modifications) bad =
true;
1453 if ( !strlen( modifications ) )
1456 fprintf( stderr,
"Cannot Write out unit file %s %s that has no filename\n",
name.get().c_str(),
csvRow.get().c_str() );
1459 std::string savedir = modifications;
1464 fprintf( stderr,
"!!! ERROR : Writing saved unit file : %s\n", f.
GetFullPath().c_str() );
1468 f.
Write( towrite.c_str(), towrite.length() );
1474 (*ui)->WriteUnit( modifications );
1480 static void mapToStringVec( vsUMap< string, string >
a, vector< string > &key, vector< string > &value )
1482 for (vsUMap< string, string >::iterator
i = a.begin();
i != a.end(); ++
i) {
1483 key.push_back(
i->first );
1484 value.push_back(
i->second );
1487 static string tos(
float val )
1492 static string tos(
double val )
1497 static string tos(
unsigned int val )
1524 vsUMap< string, string >unit;
1525 for (
unsigned int jj = 0; jj < row.
size(); ++jj)
1527 unit[row.
getKey( jj )] = row[jj];
1534 double unitScale =
stof( unit[
"Unit_Scale"], 1 );
1537 for (
unsigned int j = 0;
j <
mounts.size(); ++
j) {
1541 mounts[
j].GetMountLocation().Cast() );
1543 string printedname =
mounts[
j].type->weapon_name;
1548 sprintf( mnt,
";%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf}",
1552 (
double)
mounts[
j].xyscale/unitScale,
1553 (
double)
mounts[
j].zscale/unitScale,
1554 (
double) m.
getR().i,
1555 (double) m.
getR().j,
1556 (double) m.
getR().k,
1557 (double) m.
getQ().i,
1558 (double) m.
getQ().j,
1559 (double) m.
getQ().k,
1560 (double)
mounts[
j].functionality,
1561 (
double)
mounts[
j].maxfunctionality
1565 unit[
"Mounts"] = mountstr;
1569 vector< SubUnitStruct >subunits =
GetSubUnits( unit[
"Sub_Units"] );
1570 if ( subunits.size() ) {
1573 for (; k < subunits.size(); ++k)
1574 subunits[k].
filename =
"destroyed_blank";
1578 for (; j < subunits.size(); ++j)
1579 if ( (subun->
Position()-subunits[j].pos).MagnitudeSquared() < .00000001 )
1582 if ( j >= subunits.size() ) j = k;
1583 if ( j < subunits.size() )
1587 for (k = 0; k < subunits.size(); ++k) {
1589 sprintf( tmp,
";%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf;%lf}",
1599 ( (
double)
acos( subunits[k].restricted )*180./
VS_PI ) );
1600 str +=
"{"+subunits[k].filename+tmp;
1602 unit[
"Sub_Units"] = str;
1607 for (
unsigned int i = 0; i <
numCargo(); ++i) {
1610 sprintf( tmp,
";%f;%d;%f;%f;%f;%f;;%s;%s}",
1617 c->
mission ?
"true" :
"false",
1622 unit[
"Cargo"] = carg;
1626 unit[
"Fuel_Capacity"] =
tos(
fuel );
1638 unit[
"Shield_Front_Top_Right"] =
"";
1639 unit[
"Shield_Front_Top_Left"] =
"";
1640 unit[
"Shield_Back_Top_Right"] =
"";
1641 unit[
"Shield_Back_Top_Left"] =
"";
1642 unit[
"Shield_Front_Bottom_Right"] =
"";
1643 unit[
"Shield_Front_Bottom_Left"] =
"";
1644 unit[
"Shield_Back_Bottom_Right"] =
"";
1645 unit[
"Shield_Back_Bottom_Left"] =
"";
1653 unit[
"Shield_Front_Bottom_Right"] =
tos(
shield.
shield8.frontrightbottommax );
1654 unit[
"Shield_Front_Bottom_Left"] =
tos(
shield.
shield8.frontleftbottommax );
1655 unit[
"Shield_Back_Bottom_Right"] =
tos(
shield.
shield8.backrightbottommax );
1699 unit[
"Retro_Accel"] =
tos(
limits.
retro/(game_accel*game_speed) );
1700 unit[
"Left_Accel"] = unit[
"Right_Accel"] =
tos(
limits.
lateral/(game_accel*game_speed) );
1701 unit[
"Bottom_Accel"] = unit[
"Top_Accel"] =
tos(
limits.
vertical/(game_accel*game_speed) );
1733 unit[
"Cargo_Import"] = unit[
"Upgrades"] =
"";
1738 if ( trac.empty() ) trac =
"-";
1739 unit[
"Tractorability"] = trac;
1741 vector< string >keys, values;
1742 keys.push_back(
"Key" );
1743 values.push_back(
csvRow );
1748 fprintf( stderr,
"Failed to locate base mesh for %s %s %s\n",
csvRow.get().c_str(),
name.get().c_str(),
fullname.c_str() );
1753 ret = ret+( (*ui)->WriteUnitString() );
1768 for (
unsigned int j = 0;
j < addedcargoname->size(); ++
j) {
1770 carg.
content = (*addedcargoname)[
j];
1771 carg.
category = (
j < addedcargocat->size() ? (*addedcargocat)[
j] : std::string(
"Uncategorized" ) );
1775 carg.
description = ( j < addedcargodesc->size() ? (*addedcargodesc)[j] : std::string(
"No Description Added" ) );
1795 static std::string mpl =
vs_config->
getVariable(
"data",
"master_part_list",
"master_part_list" );
1797 ret->
name =
"master_part_list";
1804 vsUMap< std::string, int >::const_iterator it;
1805 for (it = table.rows.begin(); it != table.rows.end(); ++it) {
1806 CSVRow row( &table, it->second );
1809 carg.
category = row[
"categoryname"];
1811 carg.
mass =
stof( row[
"mass"], 1 );
1819 if ( !ret->
GetCargo(
"Pilot", i ) )
1820 ret->
AddCargo(
Cargo(
"Pilot",
"Contraband", 800, 1, .01, 1, 1.0, 1.0 ),
true );
1821 if ( !ret->
GetCargo(
"Hitchhiker", i ) )
1822 ret->
AddCargo(
Cargo(
"Hitchhiker",
"Passengers", 42, 1, .01, 5.0, 1.0, 1.0 ),
true );
1823 if ( !ret->
GetCargo(
"Slaves", i ) )
1824 ret->
AddCargo(
Cargo(
"Slaves",
"Contraband", 800, 1, .01, 1, 1, 1 ),
true );