attack.cpp

Go to the documentation of this file.
00001 
00006 /*
00007     This file is part of Advanced Strategic Command; http://www.asc-hq.de
00008     Copyright (C) 1994-2010  Martin Bickel  and  Marc Schellenberger
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU General Public License for more details.
00019 
00020     You should have received a copy of the GNU General Public License
00021     along with this program; see the file COPYING. If not, write to the 
00022     Free Software Foundation, Inc., 59 Temple Place, Suite 330,
00023     Boston, MA  02111-1307  USA
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;  // = +140% !
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 //      if ( dist <= 10 && dv.strength > 0 )
00188 //         av.experience += 1;
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       // if ( dist <= maxmalq )
00300          av.attackbonus  = field->getattackbonus();
00301       //else
00302       //   av.attackbonus = 0;
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    /* If the attacking vehicle was destroyed, remove it */
00423    if ( av.damage >= 100 ) {
00424      *_pattackingunit = NULL;
00425    }
00426 
00427    /* If the attacked vehicle was destroyed, remove it */
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       // if ( dist <= maxmalq )
00497          av.attackbonus  = field->getattackbonus();
00498       //else
00499       //   av.attackbonus = 0;
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; // getfield ( x, y ) -> getdefensebonus();
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       // if ( dist <= maxmalq )
00717          av.attackbonus  = field2->getattackbonus();
00718       //else
00719       //   av.attackbonus = 0;
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; // field  -> getdefensebonus();
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 //   if ( attacker->getMap()->player[attacker->getOwner()].diplomacy.isHostile( target->getOwner() )  )
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    if (vehicle == NULL)
01002       return ( false );
01003    if (field == NULL)
01004       return ( false );
01005    if (field->vehicle == NULL)
01006       return ( false );
01007 
01008    if ((vehicle->color != field->vehicle->color) &&
01009       (vehicle->height == chfahrend) &&
01010       (field->vehicle->height == chfahrend) && 
01011       (field->vehicle->functions & cftrooper) && 
01012       (vehicle->weight() >= fusstruppenplattfahrgewichtsfaktor * field->vehicle->weight()))
01013       return ( true ); 
01014    return ( false );
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   int         translat[31]  = { 6, 255, 1, 3, 2, 4, 0, 5, 255, 255, 6, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
01023                                  255, 255, 255, 255, 255, 255};
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 )     // mine
01034       return 1;
01035 
01036       /*
01037    int typ = translat[ scalar ];
01038    if ( typ == 255 ) {
01039       displaymessage("tweapdist::getweapstrength: invalid type ", 1 );
01040       return 1;
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 //   int minstrength = 255 - 255 * weap->minstrength / weap->maxstrength;
01064 
01065 //   int relstrength = 255 - ( 255 - data[typ][reldiff] ) * minstrength / ( 255 - data[typ][255] );
01066 
01067    float relpos = float(reldiff) / 255.0;
01068 
01069 /*   if ( weap->maxstrength && weap->minstrength )
01070       relpos /= float(weap->maxstrength) / float(weap->minstrength);
01071 
01072    return 1.0 - relpos;*/
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 /*   if ( attacker_height != -1 && defender_height!= -1 ) {
01100       int hd = getheightdelta ( getFirstBit ( attacker_height ), getFirstBit ( defender_height ));
01101       return relstrength * weap->efficiency[6+hd] / 100 ;
01102    } else
01103       return relstrength ;
01104       */
01105 }
01106 
01107 

Generated on Mon May 21 01:26:28 2012 for Advanced Strategic Command by  doxygen 1.5.1