00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <stdio.h>
00029 #include <math.h>
00030 #include <iostream>
00031
00032 #include "typen.h"
00033 #include "buildingtype.h"
00034 #include "vehicletype.h"
00035 #include "attack.h"
00036 #include "spfst.h"
00037 #include "gameoptions.h"
00038
00039 #include "actions/changeunitproperty.h"
00040 #include "actions/consumeammo.h"
00041 #include "actions/registerunitrftarget.h"
00042 #include "actions/inflictdamage.h"
00043 #include "actions/removemine.h"
00044 #include "actions/removeobject.h"
00045 #include "actions/changeobjectproperty.h"
00046
00047
00048 AttackFormula::AttackFormula( GameMap* gamemap )
00049 {
00050 this->gamemap = gamemap;
00051 }
00052
00053 bool AttackFormula :: checkHemming ( Vehicle* d_eht, int direc )
00054 {
00055 Vehicle* s_eht;
00056
00057 int x = d_eht->xpos;
00058 int y = d_eht->ypos;
00059 getnextfield(x, y, direc);
00060 MapField* fld = d_eht->getMap()->getField(x,y);
00061
00062 if ( fld )
00063 s_eht = fld->vehicle;
00064 else
00065 s_eht = NULL;
00066
00067 if ( !s_eht )
00068 return false;
00069
00070 if ( s_eht->height >= chtieffliegend || d_eht->height >= chtieffliegend )
00071 return false;
00072
00073 return attackpossible2n ( s_eht, d_eht );
00074 }
00075
00076
00077 float AttackFormula :: getHemmingFactor ( int relDir )
00078 {
00079 const float maxHemmingFactor = 1.4;
00080 const float hemming[sidenum-1] = { 4, 11, 16, 11, 4 };
00081 const float maxHemmingSum = 46;
00082 relDir %= 6;
00083 if ( relDir < 0 )
00084 relDir += sidenum;
00085
00086 if ( relDir == 5 )
00087 warningMessage("float AttackFormula :: getHemmingFactor - invalid direction" );
00088
00089 return hemming[relDir]*maxHemmingFactor/maxHemmingSum;
00090 }
00091
00092
00093 float AttackFormula :: strength_hemming ( int ax, int ay, Vehicle* d_eht )
00094 {
00095 float hemm = 0;
00096 int attackDir = getdirection(ax,ay,d_eht->xpos,d_eht->ypos);
00097 for ( int i = 0; i < sidenum-1; i++) {
00098
00099 int direc = i+1 + (attackDir-sidenum/2);
00100 if (direc < 0)
00101 direc += sidenum;
00102
00103 if (direc >= sidenum)
00104 direc -= sidenum;
00105
00106 if ( checkHemming (d_eht,direc ))
00107 hemm += getHemmingFactor(i);
00108 }
00109
00110 return hemm + 1;
00111 }
00112
00113
00114 float AttackFormula :: strength_damage ( int damage )
00115 {
00116 return 1 - (2.0 * float(damage) / 300.0);
00117 }
00118
00119 float AttackFormula :: strength_experience ( int experience )
00120 {
00121 float e = (experience < 0)
00122 ? 0
00123 : experience ;
00124 return e/maxunitexperience * 2.875 / gamemap->getgameparameter( cgp_experienceDivisorAttack );
00125 }
00126
00127 float AttackFormula :: defense_experience ( int experience )
00128 {
00129 float e = (experience < 0)
00130 ? 0
00131 : experience ;
00132
00133 return e/maxunitexperience * 1.15 / gamemap->getgameparameter( cgp_experienceDivisorDefense );
00134 }
00135
00136 float AttackFormula :: strength_attackbonus ( int abonus )
00137 {
00138 float a = abonus;
00139 return a/8;
00140 }
00141
00142
00143 float AttackFormula :: defense_defensebonus ( int defensebonus )
00144 {
00145 float d = defensebonus;
00146 return d/8;
00147 }
00148
00149
00150
00151 void tfight :: calc ( void )
00152 {
00153 int damagefactor = gamemap->getgameparameter ( cgp_attackPower );
00154 const float armordivisor = 5;
00155
00156
00157 if ( av.strength ) {
00158 float absstrength = float(av.strength )
00159 * ( 1 + strength_experience ( av.experience ) + strength_attackbonus ( av.attackbonus ) )
00160 * strength_damage ( av.damage )
00161 * dv.hemming;
00162
00163 float absdefense = float(dv.armor / armordivisor )
00164 * ( 1 + defense_defensebonus ( dv.defensebonus ) + defense_experience ( dv.experience ) );
00165
00166 int w = int( ceil(dv.damage + absstrength / absdefense * 1000 / damagefactor ));
00167
00168 if (dv.damage > w )
00169 warningMessage("fatal error at attack: \ndecrease of damage d!");
00170
00171 if (dv.damage == w )
00172 w = dv.damage+1;
00173
00174 if (w > 100)
00175 dv.damage = 100;
00176 else
00177 dv.damage = w;
00178
00179 if ( av.weapcount > 0 )
00180 av.weapcount--;
00181 else
00182 av.weapcount = 0;
00183
00184
00185 av.experience++;
00186
00187
00188
00189
00190 if ( dv.damage >= 100 )
00191 av.experience += 1;
00192
00193
00194
00195 if ( av.experience > maxunitexperience )
00196 av.experience = maxunitexperience;
00197
00198 }
00199
00200 if ( dv.strength ) {
00201 float absstrength = float(dv.strength )
00202 * ( 1 + strength_experience ( dv.experience ) + strength_attackbonus ( dv.attackbonus ) )
00203 * strength_damage ( dv.damage ) ;
00204
00205 float absdefense = float(av.armor / armordivisor)
00206 * ( 1 + defense_defensebonus ( av.defensebonus )+ defense_experience ( av.experience ));
00207
00208 int w = int( ceil(av.damage + absstrength / absdefense * 1000 / damagefactor ));
00209
00210 if (av.damage > w )
00211 warningMessage("fatal error at attack: \ndecrease of damage a!");
00212
00213 if (w > 100)
00214 av.damage = 100;
00215 else
00216 av.damage = w;
00217
00218
00219 if ( dv.weapcount > 0 )
00220 dv.weapcount--;
00221 else
00222 dv.weapcount = 0;
00223
00224 if ( av.damage >= 100 ) {
00225 dv.experience += 2;
00226 if ( dv.experience > maxunitexperience )
00227 dv.experience = maxunitexperience;
00228
00229 } else
00230 if ( dv.experience < maxunitexperience )
00231 dv.experience++;
00232 }
00233
00234 if ( av.kamikaze )
00235 av.damage = 100;
00236
00237 }
00238
00239
00240
00241 tunitattacksunit :: tunitattacksunit ( Vehicle* &attackingunit, Vehicle* &attackedunit, bool respond, int weapon, bool reactionfire )
00242 : UnitAttacksSomething( attackingunit->getMap() )
00243 {
00244 this->reactionfire = reactionfire;
00245 setup ( attackingunit, attackedunit, respond, weapon );
00246 }
00247
00248 void tunitattacksunit :: setup ( Vehicle* &attackingunit, Vehicle* &attackedunit, bool respond, int weapon )
00249 {
00250 _attackingunit = attackingunit;
00251 _attackedunit = attackedunit;
00252
00253 _pattackingunit = &attackingunit;
00254 _pattackedunit = &attackedunit;
00255
00256 dist = beeline ( attackingunit->xpos, attackingunit->ypos, attackedunit->xpos, attackedunit->ypos );
00257 int _weapon;
00258
00259 if ( weapon == -1 ) {
00260 AttackWeap* atw = attackpossible( attackingunit, attackedunit->xpos, attackedunit->ypos );
00261 int n = -1;
00262 int s = 0;
00263 for ( int i = 0; i < atw->count; i++ )
00264 if ( atw->strength[i] > s ) {
00265 s = atw->strength[i];
00266 n = i;
00267 }
00268
00269 _weapon = atw->num[n];
00270
00271 delete atw;
00272
00273 } else
00274 _weapon = weapon;
00275
00276 const SingleWeapon* weap = attackingunit->getWeapon(_weapon);
00277
00278
00279 int targetWeather = attackedunit->getMap()->getField( attackedunit->getPosition() )->getWeather();
00280
00281 av.strength = int ( ceil( attackingunit->weapstrength[_weapon]
00282 * WeapDist::getWeaponStrength(weap, targetWeather, dist, attackingunit->height, attackedunit->height )
00283 * attackingunit->typ->weapons.weapon[_weapon].targetingAccuracy[attackedunit->typ->movemalustyp] / 100 ));
00284 av.armor = attackingunit->getArmor();
00285 av.damage = attackingunit->damage;
00286 av.experience = attackingunit->experience;
00287 av.hemming = 1;
00288 av.weapnum = _weapon;
00289 av.weapcount = attackingunit->ammo [ _weapon ];
00290 av.color = attackingunit->getOwner();
00291 av.initiative = attackingunit->typ->initiative;
00292 av.kamikaze = attackingunit->typ->hasFunction( ContainerBaseType::KamikazeOnly );
00293 av.height = attackingunit->height;
00294 av.weapontype = attackingunit->typ->weapons.weapon[ _weapon ].getScalarWeaponType();
00295
00296 MapField* field = attackingunit->getMap()->getField ( attackingunit->xpos, attackingunit->ypos );
00297
00298 if ( attackingunit->height <= chfahrend ) {
00299
00300 av.attackbonus = field->getattackbonus();
00301
00302
00303 av.defensebonus = field->getdefensebonus();
00304 } else {
00305 av.attackbonus = 0;
00306 av.defensebonus = 0;
00307 }
00308
00309
00310 dv.weapnum = -1;
00311 if ( dist <= maxmalq && respond && !av.kamikaze && fieldvisiblenow( field, attackedunit->getOwner()) ) {
00312 AttackWeap atw;
00313 attackpossible2n ( attackedunit, attackingunit, &atw );
00314 int n = -1;
00315 int s = 0;
00316 for ( int i = 0; i < atw.count; i++ )
00317 if ( atw.strength[i] > s ) {
00318 s = atw.strength[i];
00319 n = i;
00320 }
00321
00322 if ( n < 0 )
00323 respond = 0;
00324 else
00325 dv.weapnum = atw.num [ n ];
00326
00327 } else
00328 respond = 0;
00329
00330 if ( attackedunit->typ->hasFunction( ContainerBaseType::KamikazeOnly ))
00331 respond = 0;
00332
00333 if ( respond ) {
00334 weap = attackedunit->getWeapon( dv.weapnum );
00335
00336
00337 int attackerWeather = attackingunit->getMap()->getField( attackingunit->getPosition() )->getWeather();
00338
00339 dv.strength = int ( ceil( attackedunit->weapstrength[ dv.weapnum ]
00340 * WeapDist::getWeaponStrength(weap, attackerWeather, dist, attackedunit->height, attackingunit->height )
00341 * attackedunit->typ->weapons.weapon[ dv.weapnum ].targetingAccuracy[attackingunit->typ->movemalustyp] / 100 ));
00342 field = attackingunit->getMap()->getField ( attackedunit->xpos, attackedunit->ypos );
00343 dv.attackbonus = field->getattackbonus();
00344 _respond = 1;
00345
00346 dv.weapcount = attackedunit->ammo [ dv.weapnum ];
00347 dv.weapontype = attackedunit->typ->weapons.weapon[ dv.weapnum ].getScalarWeaponType();
00348
00349 } else {
00350 dv.strength = 0;
00351 dv.attackbonus = 0;
00352 _respond = 0;
00353 }
00354
00355
00356 dv.armor = attackedunit->getArmor();
00357 dv.damage = attackedunit->damage;
00358 dv.experience = attackedunit->experience;
00359 if ( dist <= maxmalq && attackingunit->height < chtieffliegend )
00360 dv.hemming = strength_hemming ( attackingunit->xpos, attackingunit->ypos, attackedunit );
00361 else
00362 dv.hemming = 1;
00363
00364
00365 if ( attackedunit->height <= chfahrend )
00366 dv.defensebonus = attackedunit->getMap()->getField ( attackedunit->xpos, attackedunit->ypos ) -> getdefensebonus();
00367 else
00368 dv.defensebonus = 0;
00369
00370 dv.color = attackedunit->getOwner();
00371 dv.initiative = attackedunit->typ->initiative;
00372 dv.kamikaze = 0;
00373 dv.height = attackedunit->height;
00374 }
00375
00376
00377
00378 void log( const Vehicle* attacker, const Vehicle* attackee )
00379 {
00380 if( CGameOptions::Instance()->logKillsToConsole )
00381 std::cout << attackee->getOwner() << ";" << attacker->getOwner() << ";" << attackee->typ->id << ";"
00382 << attackee->typ->name << ";" << attackee->experience << ";" << attacker->getMap()->time.turn() << "\n" ;
00383 }
00384
00385 void tunitattacksunit :: setresult( const Context& context )
00386 {
00387 int nwid = _attackingunit->networkid;
00388 GameMap* map = _attackingunit->getMap();
00389
00390 GameAction* a = new ChangeUnitProperty( _attackingunit, ChangeUnitProperty::Experience, av.experience );
00391 a->execute ( context );
00392
00393 GameAction* b = new ConsumeAmmo( _attackingunit, _attackingunit->typ->weapons.weapon[av.weapnum].getScalarWeaponType(), av.weapnum, _attackingunit->ammo[ av.weapnum ] - av.weapcount );
00394 b->execute ( context );
00395
00396 _attackingunit->postAttack( reactionfire, context );
00397
00398 GameAction* c = new RegisterUnitRFTarget( map, nwid, av.weapnum, _attackedunit->networkid );
00399 c->execute ( context );
00400
00401 if ( _respond ) {
00402 GameAction* d = new ChangeUnitProperty( _attackedunit, ChangeUnitProperty::Experience, dv.experience );
00403 d->execute ( context );
00404
00405 GameAction* e = new ConsumeAmmo( _attackedunit, _attackedunit->typ->weapons.weapon[dv.weapnum].getScalarWeaponType(), dv.weapnum, _attackedunit->ammo[ dv.weapnum ] - dv.weapcount );
00406 e->execute ( context );
00407 }
00408
00409 GameAction* f = new InflictDamage( _attackingunit, av.damage - _attackingunit->damage );
00410 f->execute ( context );
00411
00412 if( av.damage >= 100 )
00413 log ( _attackedunit, _attackingunit );
00414
00415 if( dv.damage >= 100 )
00416 log ( _attackingunit, _attackedunit );
00417
00418 GameAction* g = new InflictDamage( _attackedunit, dv.damage - _attackedunit->damage );
00419 g->execute ( context );
00420
00421
00422
00423 if ( av.damage >= 100 ) {
00424 *_pattackingunit = NULL;
00425 }
00426
00427
00428 if ( dv.damage >= 100 ) {
00429 *_pattackedunit = NULL;
00430 }
00431 }
00432
00433
00434
00435
00436
00437
00438
00439 tunitattacksbuilding :: tunitattacksbuilding ( Vehicle* attackingunit, int x, int y, int weapon )
00440 : UnitAttacksSomething( attackingunit->getMap() )
00441 {
00442 setup ( attackingunit, x, y, weapon );
00443 }
00444
00445
00446 void tunitattacksbuilding :: setup ( Vehicle* attackingunit, int x, int y, int weapon )
00447 {
00448 _attackingunit = attackingunit;
00449 _x = x;
00450 _y = y;
00451 _attackedbuilding = attackingunit->getMap()->getField ( x, y ) -> building;
00452
00453 dist = beeline ( attackingunit->xpos, attackingunit->ypos, x, y );
00454 int _weapon;
00455
00456 if ( weapon == -1 ) {
00457 AttackWeap* atw = attackpossible( attackingunit, x, y );
00458 int n = -1;
00459 int s = 0;
00460 for ( int i = 0; i < atw->count; i++ )
00461 if ( atw->strength[i] > s ) {
00462 s = atw->strength[i];
00463 n = i;
00464 }
00465
00466 _weapon = atw->num[n];
00467
00468 delete atw;
00469 } else
00470 _weapon = weapon;
00471
00472 const SingleWeapon *weap = &attackingunit->typ->weapons.weapon[_weapon];
00473
00474 int targetWeather = attackingunit->getMap()->getField(x,y)->getWeather();
00475
00476 av.strength = int (ceil( attackingunit->weapstrength[_weapon]
00477 * WeapDist::getWeaponStrength(weap, targetWeather, dist, attackingunit->height, _attackedbuilding->typ->height )
00478 * attackingunit->typ->weapons.weapon[_weapon].targetingAccuracy[cmm_building] / 100 ));
00479
00480 av.armor = attackingunit->getArmor();
00481 av.damage = attackingunit->damage;
00482 av.experience = attackingunit->experience;
00483 av.hemming = 1;
00484 av.weapnum = _weapon;
00485 av.weapcount = attackingunit->ammo [ _weapon ];
00486 av.weapontype = attackingunit->typ->weapons.weapon[ _weapon ].getScalarWeaponType();
00487 av.color = attackingunit->getOwner();
00488 av.initiative = attackingunit->typ->initiative;
00489 av.kamikaze = attackingunit->typ->hasFunction( ContainerBaseType::KamikazeOnly );
00490 av.height = attackingunit->height;
00491
00492 MapField* field = attackingunit->getMap()->getField ( attackingunit->xpos, attackingunit->ypos );
00493
00494 if ( attackingunit->height <= chfahrend ) {
00495 av.defensebonus = field->getdefensebonus();
00496
00497 av.attackbonus = field->getattackbonus();
00498
00499
00500 } else {
00501 av.defensebonus = 0;
00502 av.attackbonus = 0;
00503 }
00504
00505
00506 dv.strength = 0;
00507 dv.attackbonus = 0;
00508
00509
00510 dv.armor = _attackedbuilding->getArmor();
00511 dv.damage = _attackedbuilding->damage;
00512 dv.experience = 0;
00513 dv.hemming = 1;
00514 dv.weapnum = -1;
00515
00516 dv.defensebonus = 0;
00517 dv.color = _attackedbuilding->getOwner();
00518 dv.initiative = 0;
00519 dv.kamikaze = 0;
00520 dv.height = _attackedbuilding->typ->height;
00521 }
00522
00523
00524 void tunitattacksbuilding :: setresult( const Context& context )
00525 {
00526 MapCoordinate target = _attackedbuilding->getPosition();
00527
00528 GameAction* b = new ConsumeAmmo( _attackingunit, _attackingunit->typ->weapons.weapon[av.weapnum].getScalarWeaponType(), av.weapnum, _attackingunit->ammo[ av.weapnum ] - av.weapcount );
00529 b->execute ( context );
00530
00531 _attackingunit->postAttack( false, context );
00532
00533 GameAction* f = new InflictDamage( _attackingunit, av.damage - _attackingunit->damage );
00534 f->execute ( context );
00535
00536 GameAction* g = new InflictDamage( _attackedbuilding, dv.damage - _attackedbuilding->damage );
00537 g->execute ( context );
00538 }
00539
00540
00541
00542 tmineattacksunit :: tmineattacksunit ( const MapCoordinate& mineposition, int minenum, Vehicle* &attackedunit )
00543 : tfight( attackedunit->getMap() )
00544 {
00545 setup ( mineposition, minenum, attackedunit );
00546 }
00547
00548 void tmineattacksunit :: setup ( const MapCoordinate& position, int minenum, Vehicle* &attackedunit )
00549 {
00550 this->position = position;
00551
00552 MapField* mineposition = attackedunit->getMap()->getField( position );
00553
00554 if ( mineposition->mines.empty() )
00555 errorMessage(" tmineattacksunit :: setup \n no mine to attack !\n" );
00556
00557 if ( attackedunit->height >= chtieffliegend )
00558 errorMessage(" tmineattacksunit :: setup \n mine attacks flying unit!\n" );
00559
00560 dist = 10;
00561
00562 _mineposition = mineposition;
00563 _attackedunit = attackedunit;
00564 _pattackedunit = &attackedunit;
00565
00566
00567 _minenum = minenum;
00568
00569 if ( minenum == -1 ) {
00570 int cnt = 1;
00571 av.strength = 0;
00572 for ( MapField::MineContainer::iterator m = mineposition->mines.begin(); m != mineposition->mines.end(); m++ )
00573 if ( m->attacksunit ( attackedunit )) {
00574 int strength = m->strength;
00575 if ( m->type == cmantipersonnelmine && (attackedunit->typ->movemalustyp == cmm_trooper ) )
00576 strength *= 2;
00577
00578 for ( int j = 1; j < cnt; j++ )
00579 strength = strength * 2 / 3;
00580
00581 av.strength += strength;
00582 cnt++;
00583 }
00584 } else {
00585 Mine& m = mineposition->getMine ( minenum );
00586 av.strength = m.strength;
00587 if ( m.type == cmantipersonnelmine && (attackedunit->typ->movemalustyp == cmm_trooper ) )
00588 av.strength *= 2;
00589 }
00590
00591 av.armor = 1;
00592 av.damage = 0;
00593 av.experience = 0;
00594 av.defensebonus = 0;
00595 av.hemming = 1;
00596 av.weapnum = 0;
00597 av.weapcount = 1;
00598 av.color = 8;
00599 av.initiative = 256;
00600 av.attackbonus = 8;
00601 av.kamikaze = 0;
00602 av.height = 0;
00603 av.weapontype = cwminen;
00604
00605 dv.strength = 0;
00606 dv.armor = attackedunit->getArmor();
00607 dv.damage = attackedunit->damage;
00608 dv.experience = attackedunit->experience;
00609 dv.defensebonus = 0;
00610 dv.hemming = 1;
00611 dv.weapnum = 0;
00612 dv.weapcount = 0;
00613 dv.color = attackedunit->getOwner();
00614 dv.initiative = attackedunit->typ->initiative;
00615 dv.attackbonus = 0;
00616 dv.kamikaze = 0;
00617 dv.height = attackedunit->height;
00618 }
00619
00620
00621 void tmineattacksunit :: setresult( const Context& context )
00622 {
00623 vector<GameAction*> actions;
00624 if ( _minenum == -1 ) {
00625 for ( MapField::MineContainer::iterator m = _mineposition->mines.begin(); m != _mineposition->mines.end(); ++m)
00626 if ( m->attacksunit ( _attackedunit ))
00627 actions.push_back ( new RemoveMine(_attackedunit->getMap(), position, m->identifier));
00628 } else {
00629 int counter = 0;
00630 for ( MapField::MineContainer::iterator m = _mineposition->mines.begin(); m != _mineposition->mines.end(); ++m, ++counter)
00631 if ( counter == _minenum )
00632 actions.push_back ( new RemoveMine(_attackedunit->getMap(), position, m->identifier));
00633 }
00634
00635 for ( vector<GameAction*>::iterator i = actions.begin(); i != actions.end(); ++i )
00636 (*i)->execute( context );
00637
00638
00639 (new InflictDamage( _attackedunit, dv.damage - _attackedunit->damage ))->execute ( context );
00640
00641 }
00642
00643
00644 Mine* tmineattacksunit :: getFirstMine()
00645 {
00646 if ( _mineposition && _mineposition->mines.size() )
00647 return &( * _mineposition->mines.begin() );
00648 else
00649 return NULL;
00650 }
00651
00652
00653
00654 tunitattacksobject :: tunitattacksobject ( Vehicle* attackingunit, int obj_x, int obj_y, int weapon )
00655 : UnitAttacksSomething( attackingunit->getMap() )
00656 {
00657 setup ( attackingunit, obj_x, obj_y, weapon );
00658 }
00659
00660 void tunitattacksobject :: setup ( Vehicle* attackingunit, int obj_x, int obj_y, int weapon )
00661 {
00662
00663 _x = obj_x;
00664 _y = obj_y;
00665
00666 targetField = attackingunit->getMap()->getField ( obj_x, obj_y );
00667
00668 _attackingunit = attackingunit;
00669
00670 dist = beeline ( attackingunit->xpos, attackingunit->ypos, obj_x, obj_y );
00671
00672 for ( MapField::ObjectContainer::reverse_iterator o = targetField->objects.rbegin(); o != targetField->objects.rend(); o++ )
00673 if ( o->typ->armor > 0 ) {
00674 _obji = &(*o);
00675 break;
00676 }
00677
00678 int _weapon;
00679
00680 if ( weapon == -1 ) {
00681
00682 AttackWeap* atw = attackpossible( attackingunit, obj_x, obj_y );
00683 int n = -1;
00684 int s = 0;
00685 for ( int i = 0; i < atw->count; i++ )
00686 if ( atw->strength[i] > s ) {
00687 s = atw->strength[i];
00688 n = i;
00689 }
00690
00691 _weapon = atw->num[n];
00692
00693 delete atw;
00694
00695 } else
00696 _weapon = weapon;
00697
00698 const SingleWeapon *weap = &attackingunit->typ->weapons.weapon[_weapon];
00699 av.strength = int ( ceil( attackingunit->weapstrength[_weapon]
00700 * WeapDist::getWeaponStrength(weap, targetField->getWeather(), dist, attackingunit->height, _obji->typ->getEffectiveHeight() )
00701 * attackingunit->typ->weapons.weapon[_weapon].targetingAccuracy[cmm_building] / 100 ));
00702
00703 av.armor = attackingunit->getArmor();
00704 av.damage = attackingunit->damage;
00705 av.experience = attackingunit->experience;
00706 av.weapnum = _weapon;
00707 av.weapcount = attackingunit->ammo [ _weapon ];
00708 av.kamikaze = attackingunit->typ->hasFunction( ContainerBaseType::KamikazeOnly );
00709 av.height = attackingunit->height;
00710 av.weapontype = attackingunit->typ->weapons.weapon[ _weapon ].getScalarWeaponType();
00711
00712 MapField* field2 = attackingunit->getMap()->getField ( attackingunit->xpos, attackingunit->ypos );
00713
00714 if ( attackingunit->height <= chfahrend ) {
00715 av.defensebonus = field2->getdefensebonus();
00716
00717 av.attackbonus = field2->getattackbonus();
00718
00719
00720 } else {
00721 av.defensebonus = 0;
00722 av.attackbonus = 0;
00723 }
00724
00725
00726 dv.strength = 0;
00727 dv.attackbonus = 0;
00728
00729 dv.armor = _obji->typ->armor;
00730 dv.damage = _obji->damage;
00731 dv.experience = 0;
00732
00733 dv.defensebonus = 0;
00734 dv.hemming = 1;
00735 dv.color = 8 ;
00736 dv.kamikaze = 0;
00737 dv.height = 0;
00738 }
00739
00740
00741
00742 void tunitattacksobject :: setresult( const Context& context )
00743 {
00744 GameMap* map = _attackingunit->getMap();
00745
00746 GameAction* b = new ConsumeAmmo( _attackingunit, _attackingunit->typ->weapons.weapon[av.weapnum].getScalarWeaponType(), av.weapnum, _attackingunit->ammo[ av.weapnum ] - av.weapcount );
00747 b->execute ( context );
00748
00749 _attackingunit->postAttack( false, context );
00750
00751 GameAction* f = new InflictDamage( _attackingunit, av.damage - _attackingunit->damage );
00752 f->execute ( context );
00753
00754
00755 MapCoordinate position( _x, _y );
00756
00757 if ( dv.damage >= 100 ) {
00758 (new RemoveObject(map, position, _obji->typ->id))->execute(context);
00759 } else {
00760 GameAction* g = new ChangeObjectProperty( map, position, _obji, ChangeObjectProperty::Damage, dv.damage );
00761 g->execute ( context );
00762 }
00763 }
00764
00765
00766
00767
00768
00769 AttackWeap* attackpossible( const Vehicle* attacker, int x, int y)
00770 {
00771 AttackWeap* atw = new AttackWeap;
00772
00773 memset(atw, 0, sizeof(*atw));
00774
00775
00776 if ((x < 0) || (y < 0) || (x >= attacker->getMap()->xsize) || (y >= attacker->getMap()->ysize))
00777 return atw;
00778 if (attacker == NULL)
00779 return atw;
00780 if (attacker->typ->weapons.count == 0)
00781 return atw;
00782
00783 MapField* efield = attacker->getMap()->getField(x,y);
00784
00785 if ( efield->getVehicle() ) {
00786 if (fieldvisiblenow(efield, attacker->color/8))
00787 attackpossible2n ( attacker, efield->getVehicle(), atw );
00788 }
00789 else if (efield->building != NULL) {
00790 if ( attacker->getMap()->getPlayer(attacker).diplomacy.isHostile( efield->building->getOwner() ) || efield->building->color == 8*8 )
00791 for (int i = 0; i < attacker->typ->weapons.count ; i++)
00792 if (attacker->typ->weapons.weapon[i].shootable() )
00793 if (attacker->typ->weapons.weapon[i].offensive() )
00794 if ( attacker->typ->weapons.weapon[i].targetingAccuracy[cmm_building] > 0 ) {
00795 int tm = efield->building->typ->height;
00796 if (tm & attacker->typ->weapons.weapon[i].targ) {
00797 if (fieldvisiblenow(efield, attacker->color/8)) {
00798 int d = beeline(attacker->xpos,attacker->ypos,x,y);
00799 if (d <= attacker->typ->weapons.weapon[i].maxdistance)
00800 if (d >= attacker->typ->weapons.weapon[i].mindistance) {
00801 if (attacker->height & attacker->typ->weapons.weapon[i].sourceheight)
00802 if ( attacker->typ->weapons.weapon[i].efficiency[6 + getheightdelta ( getFirstBit( attacker->height), getFirstBit(tm))] )
00803 if (attacker->ammo[i] > 0) {
00804 atw->strength[atw->count ] = attacker->weapstrength[i];
00805 atw->typ[atw->count ] = 1 << attacker->typ->weapons.weapon[i].getScalarWeaponType() ;
00806 atw->num[atw->count ] = i;
00807 atw->target = AttackWeap::building;
00808 atw->count++;
00809 }
00810
00811 }
00812 }
00813 }
00814 }
00815 } else if ( efield->objects.size() ) {
00816 int n = 0;
00817 for ( MapField::ObjectContainer::iterator j = efield->objects.begin(); j != efield->objects.end(); j++ )
00818 if ( j->typ->armor > 0 )
00819 n++;
00820
00821 if ( n > 0 )
00822 if ((efield->vehicle == NULL) && ( efield->building == NULL)) {
00823 bool found = false;
00824 for ( MapField::ObjectContainer::reverse_iterator j = efield->objects.rbegin(); j != efield->objects.rend(); ++j ) {
00825 for ( int i = 0; i <= attacker->typ->weapons.count - 1; i++)
00826 if (attacker->typ->weapons.weapon[i].shootable() )
00827 if ( attacker->typ->weapons.weapon[i].getScalarWeaponType() == cwcannonn ||
00828 attacker->typ->weapons.weapon[i].getScalarWeaponType() == cwlasern ||
00829 attacker->typ->weapons.weapon[i].getScalarWeaponType() == cwcruisemissile ||
00830 attacker->typ->weapons.weapon[i].getScalarWeaponType() == cwlargemissilen ||
00831 attacker->typ->weapons.weapon[i].getScalarWeaponType() == cwsmallmissilen ||
00832 attacker->typ->weapons.weapon[i].getScalarWeaponType() == cwtorpedon ||
00833 attacker->typ->weapons.weapon[i].getScalarWeaponType() == cwbombn ) {
00834 if ( attacker->typ->weapons.weapon[i].targetingAccuracy[cmm_building] )
00835 if (fieldvisiblenow(efield, attacker->color/8)) {
00836 int d = beeline(attacker->xpos,attacker->ypos,x,y);
00837 if (d <= attacker->typ->weapons.weapon[i].maxdistance)
00838 if (d >= attacker->typ->weapons.weapon[i].mindistance) {
00839 if (attacker->height & attacker->typ->weapons.weapon[i].sourceheight )
00840 if ( attacker->typ->weapons.weapon[i].targ & j->typ->getEffectiveHeight() )
00841 if ( attacker->typ->weapons.weapon[i].efficiency[6 + getheightdelta ( getFirstBit( attacker->height), getFirstBit(j->typ->getEffectiveHeight()))] )
00842 if (attacker->ammo[i] > 0) {
00843 atw->strength[atw->count ] = attacker->weapstrength[i];
00844 atw->num[atw->count ] = i;
00845 atw->typ[atw->count ] = 1 << attacker->typ->weapons.weapon[i].getScalarWeaponType();
00846 atw->target = AttackWeap::object;
00847 atw->count++;
00848 found = true;
00849 }
00850
00851 }
00852 }
00853
00854 }
00855 if ( found )
00856 return atw;
00857 }
00858
00859 }
00860 }
00861
00862 return atw;
00863 }
00864
00865
00866 bool attackpossible2u( const Vehicle* attacker, const Vehicle* target, AttackWeap* atw, int targetheight )
00867 {
00868 if ( targetheight == -1 )
00869 targetheight = target->height;
00870
00871 int result = false;
00872 if ( atw )
00873 atw->count = 0;
00874
00875 if ( !attacker )
00876 return false ;
00877
00878 if ( !target )
00879 return false ;
00880
00881 if (attacker->typ->weapons.count == 0)
00882 return false ;
00883
00884 if ( attacker->getMap()->player[attacker->getOwner()].diplomacy.isHostile( target->getOwner() ) )
00885 for ( int i = 0; i < attacker->typ->weapons.count ; i++)
00886 for ( int h = 0; h < 8; h++ )
00887 if ( targetheight & (1<<h))
00888 if (attacker->typ->weapons.weapon[i].shootable() )
00889 if (attacker->typ->weapons.weapon[i].offensive() )
00890 if ( (1<<h) & attacker->typ->weapons.weapon[i].targ )
00891 if (attacker->height & attacker->typ->weapons.weapon[i].sourceheight )
00892 if ( attacker->typ->weapons.weapon[i].targetingAccuracy[ target->typ->movemalustyp] > 0 )
00893 if ( attacker->typ->weapons.weapon[i].efficiency[6 + getheightdelta ( getFirstBit( attacker->height), h)] )
00894 if (attacker->ammo[i] > 0) {
00895 result = true;
00896 if ( atw ) {
00897 atw->strength[atw->count] = attacker->weapstrength[i] * attacker->typ->weapons.weapon[i].targetingAccuracy[ target->typ->movemalustyp] / 100;
00898 atw->num[atw->count ] = i;
00899 atw->typ[atw->count ] = 1 << attacker->typ->weapons.weapon[i].getScalarWeaponType();
00900 atw->target = AttackWeap::vehicle;
00901 atw->count++;
00902 }
00903 }
00904
00905 return result;
00906 }
00907
00908
00909
00910 bool attackpossible28( const Vehicle* attacker, const Vehicle* target, AttackWeap* atw, int targetHeight )
00911 {
00912 if ( targetHeight < 0 )
00913 targetHeight = target->height;
00914
00915 bool result = false;
00916 if ( atw )
00917 atw->count = 0;
00918
00919 if (attacker == NULL)
00920 return false ;
00921
00922 if (target == NULL)
00923 return false ;
00924
00925 if (attacker->typ->weapons.count == 0)
00926 return false ;
00927
00928
00929 for ( int i = 0; i < attacker->typ->weapons.count ; i++)
00930 if (attacker->typ->weapons.weapon[i].shootable() )
00931 if (attacker->typ->weapons.weapon[i].offensive() )
00932 if (targetHeight & attacker->typ->weapons.weapon[i].targ )
00933 if (minmalq <= attacker->typ->weapons.weapon[i].maxdistance)
00934 if (minmalq >= attacker->typ->weapons.weapon[i].mindistance)
00935 if (attacker->height & attacker->typ->weapons.weapon[i].sourceheight )
00936 if ( attacker->typ->weapons.weapon[i].targetingAccuracy[ target->typ->movemalustyp ] > 0)
00937 if ( attacker->typ->weapons.weapon[i].efficiency[6 + getheightdelta ( getFirstBit( attacker->height), getFirstBit(targetHeight))] )
00938 if (attacker->ammo[i] > 0) {
00939 result = true;
00940 if ( atw ) {
00941 atw->strength[atw->count] = attacker->weapstrength[i] * attacker->typ->weapons.weapon[i].targetingAccuracy[ target->typ->movemalustyp] / 100;
00942 atw->num[atw->count ] = i;
00943 atw->typ[atw->count ] = 1 << attacker->typ->weapons.weapon[i].getScalarWeaponType();
00944 atw->target = AttackWeap::vehicle;
00945 atw->count++;
00946 }
00947 }
00948
00949 return result;
00950 }
00951
00952
00953 bool attackpossible2n( const Vehicle* attacker, const Vehicle* target, AttackWeap* atw )
00954 {
00955 int result = false;
00956 if ( atw )
00957 atw->count = 0;
00958
00959 if (attacker == NULL)
00960 return false ;
00961
00962 if (target == NULL)
00963 return false ;
00964
00965 if (attacker->typ->weapons.count == 0)
00966 return false ;
00967
00968 int dist = beeline ( attacker, target );
00969 if ( attacker->getMap()->player[attacker->getOwner()].diplomacy.isHostile( target->getOwner() ) )
00970 if ( !attacker->attacked )
00971 if ( !attacker->typ->wait || !attacker->hasMoved() || attacker->reactionfire.getStatus() == Vehicle::ReactionFire::ready)
00972 for ( int i = 0; i < attacker->typ->weapons.count ; i++)
00973 if (attacker->typ->weapons.weapon[i].shootable() )
00974 if (attacker->typ->weapons.weapon[i].offensive() )
00975 if (target->height & attacker->typ->weapons.weapon[i].targ )
00976 if (dist <= attacker->typ->weapons.weapon[i].maxdistance)
00977 if (dist >= attacker->typ->weapons.weapon[i].mindistance)
00978 if (attacker->height & attacker->typ->weapons.weapon[i].sourceheight )
00979 if ( attacker->typ->weapons.weapon[i].efficiency[6 + getheightdelta ( getFirstBit( attacker->height), getFirstBit(target->height))] )
00980 if ( attacker->typ->weapons.weapon[i].targetingAccuracy[ target->typ->movemalustyp ] > 0)
00981 if (attacker->ammo[i] > 0) {
00982 result = true;
00983 if ( atw ) {
00984 atw->strength[atw->count] = attacker->weapstrength[i] * attacker->typ->weapons.weapon[i].targetingAccuracy[ target->typ->movemalustyp ] / 100;
00985 atw->num[atw->count ] = i;
00986 atw->typ[atw->count ] = 1 << attacker->typ->weapons.weapon[i].getScalarWeaponType();
00987 atw->target = AttackWeap::vehicle;
00988 atw->count++;
00989 }
00990 }
00991
00992
00993 return result;
00994 }
00995
00996 bool vehicleplattfahrbar( const Vehicle* vehicle,
00997 const MapField* field)
00998 {
00999 return false;
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016 }
01017
01018
01019 float WeapDist::getWeaponStrength ( const SingleWeapon* weap, int weather, int dist, int attacker_height, int defender_height, int reldiff )
01020 {
01021
01022
01023
01024
01025
01026 if ( !weap )
01027 return 0;
01028
01029 int scalar = weap->getScalarWeaponType();
01030 if ( scalar >= 31 || scalar < 0 )
01031 return 0;
01032
01033 if ( scalar == 1 )
01034 return 1;
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045 if ( weap->maxdistance == 0 )
01046 return 0;
01047
01048 if ( weap->minstrength == 0 )
01049 return 0;
01050
01051 if ( reldiff == -1) {
01052 if ( dist < weap->mindistance || dist > weap->maxdistance ) {
01053 warningMessage("tweapdist::getweapstrength: invalid range: \n min = " + ASCString::toString(weap->mindistance ) + " ; max = " + ASCString::toString( weap->maxdistance ) + " ; req = " + ASCString::toString( dist));
01054 return 0;
01055 }
01056
01057 if ( weap->maxdistance - weap->mindistance != 0 )
01058 reldiff = 255 * (dist - weap->mindistance) / ( weap->maxdistance - weap->mindistance) ;
01059 else
01060 reldiff = 0;
01061 }
01062
01063
01064
01065
01066
01067 float relpos = float(reldiff) / 255.0;
01068
01069
01070
01071
01072
01073
01074
01075 float relstrength = weap->maxstrength - relpos * ( weap->maxstrength - weap->minstrength );
01076
01077 float weatherFactor = 1;
01078 int heightEff = 100;
01079 if ( attacker_height != -1 && defender_height != -1 ) {
01080 int hd = getheightdelta ( getFirstBit ( attacker_height ), getFirstBit ( defender_height ));
01081 heightEff = weap->efficiency[6+hd];
01082
01083 if ( attacker_height >= chtieffliegend && weather != 0 && defender_height != -1) {
01084 int weatherRelevantHeightDelta = min( abs( getheightdelta ( getFirstBit ( attacker_height ), getFirstBit ( defender_height ))), 3);
01085 if ( weather == 1 || weather == 3 )
01086 weatherFactor = 1 - 0.07*weatherRelevantHeightDelta;
01087 else
01088 if ( weather == 2 || weather == 4 || weather == 5 )
01089 weatherFactor = 1 - 0.2 * weatherRelevantHeightDelta;
01090 }
01091
01092 if ( attacker_height == chsatellit )
01093 weatherFactor = 1 - (1-weatherFactor)/2;
01094 }
01095
01096
01097 return relstrength * heightEff * weatherFactor / float(weap->maxstrength * 100) ;
01098
01099
01100
01101
01102
01103
01104
01105 }
01106
01107