Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
weapon_xml.cpp
Go to the documentation of this file.
1 #include "star_system.h"
2 
3 #include "weapon_xml.h"
4 #include <assert.h>
5 #include "audiolib.h"
6 #include "unit_generic.h"
7 #include "beam.h"
8 #include "unit_const_cache.h"
9 #include "vsfilesystem.h"
10 #include "role_bitmask.h"
11 #include "endianness.h"
12 
13 extern enum weapon_info::MOUNT_SIZE lookupMountSize( const char *str );
14 
15 
16 #if (defined (__APPLE__) == POSH_BIG_ENDIAN) || !defined (INTEL_X86)
17 //pre-optimization bug with "gcc 3.1 (20021003) prerelease"
18 int counts = time( NULL );
19 #else
20 int counts = 0;
21 #endif
22 
24 {
26  unsigned short file_len = 0, weap_len = 0;
27  int offset = 0;
28 
29  //Get the weapon_info structure
30  memcpy( &wi, netbuf+offset, sizeof (wi) );
31  offset += sizeof (wi);
32  memcpy( &file_len, netbuf+offset, sizeof (file_len) );
33  offset += sizeof (file_len);
34  file_len = VSSwapHostShortToLittle( file_len );
35  char *filename = new char[file_len];
36  memcpy( filename, netbuf, file_len );
37  offset += file_len;
38  memcpy( &weap_len, netbuf+offset, sizeof (weap_len) );
39  offset += sizeof (weap_len);
40  weap_len = VSSwapHostShortToLittle( weap_len );
41  char *weapname = new char[weap_len];
42  memcpy( weapname, netbuf, weap_len );
43  wi.file = string( filename );
44  wi.weapon_name = string( weapname );
45  delete[] filename;
46  delete[] weapname;
47 
48  return wi;
49 }
50 
51 void setWeaponInfoToBuffer( weapon_info wi, char *netbuf, int &bufsize )
52 {
53  bufsize = sizeof (wi)+sizeof (wi.file)+sizeof (wi.weapon_name);
54  netbuf = new char[bufsize+1];
55  netbuf[bufsize] = 0;
56  int offset = 0;
57 
58  unsigned short file_len = wi.file.length();
59  unsigned short weap_len = wi.weapon_name.length();
60  char *file = new char[file_len+1];
61  char *weapon_name = new char[weap_len+1];
62  memcpy( file, wi.file.c_str(), file_len );
63  file[file_len] = 0;
64  memcpy( weapon_name, wi.weapon_name.c_str(), weap_len );
65  weapon_name[weap_len] = 0;
66 
67  //Copy the struct weapon_info in the buffer
68  memcpy( netbuf+offset, &wi, sizeof (wi) );
69  offset += sizeof (wi);
70  //Copy the size of filename in the buffer
71  memcpy( netbuf+offset, &file_len, sizeof (file_len) );
72  offset += sizeof (file_len);
73  //Copy the filename in the buffer because in weapon_info, it is a string
74  memcpy( netbuf+offset, file, file_len );
75  offset += file_len;
76  //Copy the size of filename in the buffer
77  memcpy( netbuf+offset, &weap_len, sizeof (weap_len) );
78  offset += sizeof (weap_len);
79  //Copy the weapon_name in the buffer because in weapon_info, it is a string
80  memcpy( netbuf+offset, weapon_name, weap_len );
81 
82  delete[] file;
83  delete[] weapon_name;
84 }
85 
87 {
88  //Enum elements are the size of an int
89  //byte order swap doesn't work with ENUM - MAY NEED TO FIND A WORKAROUND SOMEDAY
90  //type = VSSwapHostIntToLittle( type);
91  //size = VSSwapHostIntToLittle( size);
92  offset.netswap();
111  RefireRate = VSSwapHostFloatToLittle( RefireRate );
114 }
115 
116 #include "xml_support.h"
117 #include "physics.h"
118 #include <vector>
119 
120 #include <expat.h>
121 
122 using std::vector;
123 using XMLSupport::EnumMap;
126 
127 namespace BeamXML
128 {
129 enum Names
130 {
168 
169 };
170 
172  EnumMap::Pair( "UNKNOWN", UNKNOWN ), //don't add anything until below missile so it maps to enum WEAPON_TYPE
173  EnumMap::Pair( "Beam", BEAM ),
174  EnumMap::Pair( "Ball", BALL ),
175  EnumMap::Pair( "Bolt", BOLT ),
176  EnumMap::Pair( "Missile", PROJECTILE ),
177  EnumMap::Pair( "Weapons", WEAPONS ),
178  EnumMap::Pair( "Appearance", APPEARANCE ),
179  EnumMap::Pair( "Energy", ENERGY ),
180  EnumMap::Pair( "Damage", DAMAGE ),
181  EnumMap::Pair( "Distance", DISTANCE )
182 };
183 
185  EnumMap::Pair( "UNKNOWN", UNKNOWN ),
186  EnumMap::Pair( "Name", NAME ),
187  EnumMap::Pair( "MountSize", WEAPSIZE ),
188  EnumMap::Pair( "file", XFILE ),
189  EnumMap::Pair( "soundMp3", SOUNDMP3 ),
190  EnumMap::Pair( "soundWav", SOUNDWAV ),
191  EnumMap::Pair( "r", RED ),
192  EnumMap::Pair( "g", GREEN ),
193  EnumMap::Pair( "b", BLUE ),
194  EnumMap::Pair( "a", ALPHA ),
195  EnumMap::Pair( "Speed", SPEED ),
196  EnumMap::Pair( "Pulsespeed", PULSESPEED ),
197  EnumMap::Pair( "DetonationRange", DETONATIONRADIUS ),
198  EnumMap::Pair( "LockTime", LOCKTIME ),
199  EnumMap::Pair( "Radialspeed", RADIALSPEED ),
200  EnumMap::Pair( "Range", RANGE ),
201  EnumMap::Pair( "Radius", RADIUS ),
202  EnumMap::Pair( "Rate", RATE ),
203  EnumMap::Pair( "Damage", DAMAGE ),
204  EnumMap::Pair( "PhaseDamage", PHASEDAMAGE ),
205  EnumMap::Pair( "Stability", STABILITY ),
206  EnumMap::Pair( "Longrange", LONGRANGE ),
207  EnumMap::Pair( "Consumption", CONSUMPTION ),
208  EnumMap::Pair( "Refire", REFIRE ),
209  EnumMap::Pair( "Length", LENGTH ),
210  EnumMap::Pair( "OffsetX", OFFSETX ),
211  EnumMap::Pair( "OffsetY", OFFSETY ),
212  EnumMap::Pair( "OffsetZ", OFFSETZ ),
213  EnumMap::Pair( "Volume", VOLUME ),
214  EnumMap::Pair( "Role", ROLE ),
215  EnumMap::Pair( "AntiRole", ANTIROLE ),
216  EnumMap::Pair( "TextureStretch", TEXTURESTRETCH )
217 };
218 
219 const EnumMap element_map( element_names, 10 );
222 string curname;
224 int level = -1;
225 
226 void beginElementXML_Char( void *userData, const XML_Char *name, const XML_Char **atts )
227 {
228  beginElement( userData, (const XML_Char*) name, (const XML_Char**) atts );
229 }
230 
231 #define color_step (49)
232 
233 #define Gamma_Needed( gamma, count, depth ) \
234  ( \
235  !( \
236  ( count/(100*depth*gamma) ) \
237  %( (6*(color_step*100+depth)/gamma-1)/3 ) \
238  -100 \
239  ) \
240  )
241 
242 void beginElement( void *userData, const char *name, const char **atts )
243 {
244  static float game_speed = XMLSupport::parse_float( vs_config->getVariable( "physics", "game_speed", "1" ) );
245  static bool adj_gun_speed =
246  XMLSupport::parse_bool( vs_config->getVariable( "physics", "gun_speed_adjusted_game_speed", "false" ) );
247  static float gun_speed =
248  XMLSupport::parse_float( vs_config->getVariable( "physics", "gun_speed", "1" ) )*(adj_gun_speed ? game_speed : 1);
249  static int gamma = (int) ( 20*XMLSupport::parse_float( vs_config->getVariable( "graphics", "weapon_gamma", "1.35" ) ) );
250  AttributeList attributes( atts );
251  enum weapon_info::WEAPON_TYPE weaptyp;
252  Names elem = (Names) element_map.lookup( string( name ) );
253 #ifdef TESTBEAMSONLY
254  if (elem == BOLT)
255  elem = BEAM;
256 #endif
257  AttributeList::const_iterator iter;
258  switch (elem)
259  {
260  case UNKNOWN:
261  break;
262  case WEAPONS:
263  level++;
264  break;
265  case BOLT:
266  case BEAM:
267  case BALL:
268  case PROJECTILE:
269  level++;
270  switch (elem)
271  {
272  case BOLT:
273  weaptyp = weapon_info::BOLT;
274  break;
275  case BEAM:
276  weaptyp = weapon_info::BEAM;
277  break;
278  case BALL:
279  weaptyp = weapon_info::BALL;
280  break;
281  case PROJECTILE:
282  weaptyp = weapon_info::PROJECTILE;
283  break;
284  default:
285  weaptyp = weapon_info::UNKNOWN;
286  break;
287  }
288  tmpweapon.Type( weaptyp );
289  for (iter = attributes.begin(); iter != attributes.end(); iter++) {
290  switch ( attribute_map.lookup( (*iter).name ) )
291  {
292  case UNKNOWN:
293  VSFileSystem::vs_fprintf( stderr, "Unknown Weapon Element %s", (*iter).name.c_str() );
294  break;
295  case NAME:
296  curname = (*iter).value;
298  break;
299  case ROLE:
300  tmpweapon.role_bits = ROLES::readBitmask( iter->value );
301  break;
302  case ANTIROLE:
303  tmpweapon.role_bits = ROLES::readBitmask( iter->value );
305  break;
306  case WEAPSIZE:
307  tmpweapon.MntSize( lookupMountSize( (*iter).value.c_str() ) );
308  break;
309  default:
310  break;
311  }
312  }
313  break;
314  case APPEARANCE:
315  level++;
316  counts++;
317  for (iter = attributes.begin(); iter != attributes.end(); iter++) {
318  switch ( attribute_map.lookup( (*iter).name ) )
319  {
320  case UNKNOWN:
321  VSFileSystem::vs_fprintf( stderr, "Unknown Weapon Element %s", (*iter).name.c_str() );
322  break;
323  case XFILE:
324  tmpweapon.file = (*iter).value;
325  break;
326  case SOUNDMP3:
328  break;
329  case SOUNDWAV:
331  break;
332  case OFFSETX:
333  tmpweapon.offset.i = XMLSupport::parse_float( iter->value );
334  break;
335  case OFFSETY:
336  tmpweapon.offset.j = XMLSupport::parse_float( iter->value );
337  break;
338  case OFFSETZ:
339  tmpweapon.offset.k = XMLSupport::parse_float( iter->value );
340  break;
341  case RED:
342  tmpweapon.r = XMLSupport::parse_float( (*iter).value );
343  break;
344  case GREEN:
345  tmpweapon.g = XMLSupport::parse_float( (*iter).value );
346  break;
347  case BLUE:
348  tmpweapon.b = XMLSupport::parse_float( (*iter).value );
349  break;
350  case ALPHA:
351  tmpweapon.a = XMLSupport::parse_float( (*iter).value );
352  break;
353  case TEXTURESTRETCH:
355  XMLSupport::parse_float( (*iter).value );
356  break;
357  default:
358  break;
359  }
360  }
361  if ( (gamma > 0) && Gamma_Needed( gamma, counts, 32 ) ) {
362  //approximate the color func
363  tmpweapon.b = (tmpweapon.b+color_step*5)/255.;
364  tmpweapon.g = (tmpweapon.g+color_step/5)/255.;
365  tmpweapon.r = (tmpweapon.r+color_step*2)/255.;
366  }
367  break;
368  case ENERGY:
369  level++;
370  for (iter = attributes.begin(); iter != attributes.end(); iter++) {
371  switch ( attribute_map.lookup( (*iter).name ) )
372  {
373  case UNKNOWN:
374  VSFileSystem::vs_fprintf( stderr, "Unknown Weapon Element %s", (*iter).name.c_str() );
375  break;
376  case CONSUMPTION:
377  tmpweapon.EnergyRate = XMLSupport::parse_float( (*iter).value );
378  break;
379  case RATE:
380  tmpweapon.EnergyRate = XMLSupport::parse_float( (*iter).value );
381  break;
382  case STABILITY:
383  tmpweapon.Stability = XMLSupport::parse_float( (*iter).value );
384  break;
385  case REFIRE:
386  tmpweapon.RefireRate = XMLSupport::parse_float( (*iter).value );
387  break;
388  case LOCKTIME:
389  tmpweapon.LockTime = XMLSupport::parse_float( (*iter).value );
390  break;
391  default:
392  break;
393  }
394  }
395  break;
396  case DAMAGE:
397  {
398  static float damagemodifier =
399  XMLSupport::parse_float( vs_config->getVariable( "physics", "weapon_damage_efficiency", "1.0" ) );
400  level++;
401  for (iter = attributes.begin(); iter != attributes.end(); iter++) {
402  switch ( attribute_map.lookup( (*iter).name ) )
403  {
404  case UNKNOWN:
405  VSFileSystem::vs_fprintf( stderr, "Unknown Weapon Element %s", (*iter).name.c_str() );
406  break;
407  case DAMAGE:
408  tmpweapon.Damage = damagemodifier*XMLSupport::parse_float( (*iter).value );
409  break;
410  case RADIUS:
411  tmpweapon.Radius = XMLSupport::parse_float( (*iter).value );
412  break;
413  case RADIALSPEED:
414  tmpweapon.RadialSpeed = XMLSupport::parse_float( (*iter).value );
415  break;
416  case PHASEDAMAGE:
417  tmpweapon.PhaseDamage = damagemodifier*XMLSupport::parse_float( (*iter).value );
418  break;
419  case RATE:
420  tmpweapon.Damage = damagemodifier*XMLSupport::parse_float( (*iter).value );
421  break;
422  case LONGRANGE:
423  tmpweapon.Longrange = XMLSupport::parse_float( (*iter).value );
424  break;
425  default:
426  break;
427  }
428  }
429  break;
430  }
431  case DISTANCE:
432  level++;
433  for (iter = attributes.begin(); iter != attributes.end(); iter++) {
434  switch ( attribute_map.lookup( (*iter).name ) )
435  {
436  case UNKNOWN:
437  VSFileSystem::vs_fprintf( stderr, "Unknown Weapon Element %s", (*iter).name.c_str() );
438  break;
439  case VOLUME:
440  tmpweapon.volume = XMLSupport::parse_float( (*iter).value );
441  break;
442  case SPEED:
443  tmpweapon.Speed = XMLSupport::parse_float( (*iter).value );
444  if (tmpweapon.Speed < 1000) {
445  tmpweapon.Speed = tmpweapon.Speed*(adj_gun_speed ? (1.0+gun_speed/1.25) : gun_speed);
446  } else {
447  if (tmpweapon.Speed < 2000) {
448  tmpweapon.Speed = tmpweapon.Speed*( adj_gun_speed ? (1.0+gun_speed/2.5) : (gun_speed) );
449  } else {
450  if (tmpweapon.Speed < 4000)
451  tmpweapon.Speed = tmpweapon.Speed*( adj_gun_speed ? (1.0+gun_speed/6.0) : (gun_speed) );
452  else if (tmpweapon.Speed < 8000)
453  tmpweapon.Speed = tmpweapon.Speed*( adj_gun_speed ? (1.0+gun_speed/17.0) : (gun_speed) );
454  }
455  }
456  break;
457  case PULSESPEED:
459  tmpweapon.PulseSpeed = XMLSupport::parse_float( (*iter).value );
460  break;
461  case DETONATIONRADIUS:
463  tmpweapon.PulseSpeed = XMLSupport::parse_float( (*iter).value );
464  break;
465  case RADIALSPEED:
466  tmpweapon.RadialSpeed = XMLSupport::parse_float( (*iter).value );
467  break;
468  case RANGE:
469  tmpweapon.Range = ( adj_gun_speed ? (1.0+gun_speed/16.0) : (gun_speed) )*XMLSupport::parse_float(
470  (*iter).value );
471  break;
472  case RADIUS:
473  tmpweapon.Radius = XMLSupport::parse_float( (*iter).value );
474  break;
475  case LENGTH:
476  tmpweapon.Length = XMLSupport::parse_float( (*iter).value );
477  break;
478  default:
479  break;
480  }
481  }
482  break;
483  default:
484  break;
485  }
486 }
487 
488 #undef Gamma_Needed
489 
490 void endElement( void *userData, const XML_Char *name )
491 {
492  Names elem = (Names) element_map.lookup( name );
493  switch (elem)
494  {
495  case UNKNOWN:
496  break;
497  case WEAPONS:
498  level--;
499  break;
500  case BEAM:
501  case BOLT:
502  case BALL:
503  case PROJECTILE:
504  level--;
506  tmpweapon.init();
507  break;
508  case ENERGY:
509  case DAMAGE:
510  case DISTANCE:
511  case APPEARANCE:
512  level--;
513  break;
514  default:
515  break;
516  }
517 }
518 
519 //namespace BeamXML
520 }
521 
522 using namespace BeamXML;
523 using namespace VSFileSystem;
524 
525 weapon_info * getTemplate( const string &kkey )
526 {
527  weapon_info *wi = lookuptable.Get( strtoupper( kkey ) );
528  if (wi) {
530  static string sharedmountdir = vs_config->getVariable( "data", "mountlocation", "weapons" );
531  static FileLookupCache lookup_cache;
532  string meshname = strtolower( kkey )+".bfxm";
533  if (CachedFileLookup( lookup_cache, meshname, MeshFile ) <= Ok) {
535  Mesh::LoadMesh( meshname.c_str(), Vector( 1, 1, 1 ), 0, NULL ) );
537  Mesh::LoadMesh( meshname.c_str(), Vector( 1, 1, 1 ), 0, NULL ) );
538  }
539  }
540  }
541  return wi;
542 }
543 
544 void LoadWeapons( const char *filename )
545 {
546  using namespace VSFileSystem;
547  VSFile f;
548  VSError err = f.OpenReadOnly( filename, UnknownFile );
549  if (err > Ok)
550  return;
551  XML_Parser parser = XML_ParserCreate( NULL );
552  XML_SetElementHandler( parser, &beginElementXML_Char, &endElement );
553  XML_Parse( parser, ( f.ReadFull() ).c_str(), f.Size(), 1 );
554  f.Close();
555  XML_ParserFree( parser );
556 }
557 
558 float weapon_info::Refire() const
559 {
560  unsigned int len = weapon_name.length();
561  if (g_game.difficulty > .98 || len < 9 || weapon_name[len-8] != 'C' || weapon_name[len-9] != '_' || weapon_name[len-7]
562  != 'o' || weapon_name[len-6] != 'm' || weapon_name[len-5] != 'p' || weapon_name[len-4] != 'u' || weapon_name[len-3]
563  != 't' || weapon_name[len-2] != 'e' || weapon_name[len-1] != 'r')
564  return RefireRate;
565  static float three = XMLSupport::parse_float( vs_config->getVariable( "physics", "refire_difficutly_scaling", "3.0" ) );
566  return this->RefireRate*( three/(1.0f+(three-1.0f)*g_game.difficulty) );
567 }