File indexing completed on 2022-09-27 13:19:22

0001 /*
0002     SPDX-FileCopyrightText: 1998-2001 Andreas Zehender <az@azweb.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "ai.h"
0008 
0009 #include <math.h>
0010 
0011 #include <QVector>
0012 
0013 #include "mathroutines.h"
0014 #include "structs.h"
0015 
0016 int Ai::calcFrameIncrement[Options::EnumAiDifficulty::COUNT] = {15,8,6,2};
0017 int Ai::calcPositionNumber[Options::EnumAiDifficulty::COUNT] = {10,15,20,60};
0018 int Ai::calcShotDirections[Options::EnumAiDifficulty::COUNT] = {4,7,10,12};
0019 int Ai::calcCollisions[Options::EnumAiDifficulty::COUNT]     = {30,15,10,10};
0020 int Ai::calcNextShot[Options::EnumAiDifficulty::COUNT]       = {300,200,90,60};
0021 
0022 Ai::Ai(int pn,ShipSprite* s[2],QList<BulletSprite*>* b[2],
0023        QList<MineSprite*>* m[2],SConfig *c)
0024  : random(QRandomGenerator::securelySeeded())
0025 {
0026    int i;
0027 
0028    playerNumber=pn;
0029    opponentNumber=(pn+1)%2;
0030    cfg=c;
0031 
0032    for(i=0;i<2;++i)
0033    {
0034       ship[i]=s[i];
0035       bullets[i]=b[i];
0036       mines[i]=m[i];
0037       shipsNextPositions[i]=new QVector<AiSprite>
0038          ((int)(calcPositionNumber[Options::aiDifficulty(playerNumber)]/cfg->gamespeed));
0039       aiMines[i]=new QVector<AiSprite>(cfg->maxMines);
0040       mineNumber[i]=0;
0041    }
0042 }
0043 
0044 Ai::~Ai()
0045 {
0046    int i;
0047    
0048    for (i=0;i<2;i++)
0049    {
0050       delete shipsNextPositions[i];
0051       delete aiMines[i];
0052    }
0053    
0054    qDeleteAll(myShots);
0055    myShots.clear();
0056    
0057    qDeleteAll(objectsHitByShip);
0058    objectsHitByShip.clear();
0059    
0060    qDeleteAll(minesHitByShot);
0061    minesHitByShot.clear();
0062 }
0063 
0064 void Ai::newRound()
0065 {
0066    accelerateFramesNumber=0;
0067    rotateFramesNumber=0;
0068    shoot=false;
0069    score=1e10;
0070 
0071    rotation=RNONE;
0072    acc=false;
0073    bullet=false;
0074    mine=false;
0075 
0076    borderTime=-1;
0077    sunTime=-1;
0078 
0079    calculateCollisions=(int)(calcCollisions[Options::aiDifficulty(playerNumber)]
0080                              /cfg->gamespeed);
0081    waitShot=(int) rint( random.bounded(1.0) *
0082                  calcNextShot[Options::aiDifficulty(playerNumber)]
0083                   /cfg->gamespeed);
0084 
0085    qDeleteAll(myShots);
0086    myShots.clear();
0087    qDeleteAll(objectsHitByShip);
0088    objectsHitByShip.clear();
0089    qDeleteAll(minesHitByShot);
0090    minesHitByShot.clear();
0091 }
0092 
0093 void Ai::think()
0094 {
0095    setSpriteFieldSize();
0096 
0097    qDeleteAll(myShots);
0098    myShots.clear();
0099    borderTime=-1;
0100    sunTime=-1;
0101    score--;
0102    if(waitShot>0)
0103       waitShot--;
0104 
0105    calculateNextPositions();
0106    if(Options::aiDifficulty(playerNumber)!=Options::EnumAiDifficulty::Trainee)
0107       testForHits();
0108    if(waitShot<=0)
0109    {
0110       tryShots();
0111       shotScores();
0112    }
0113    chooseAction();
0114 
0115 
0116    if(rotateFramesNumber<=0)
0117    {
0118       rotation=RNONE;
0119       if(accelerateFramesNumber<=0)
0120       {
0121          acc=false;
0122          if(shoot)
0123          {
0124             bullet=true;
0125             shoot=false;
0126          }
0127          else
0128             bullet=false;
0129          score=1e10;
0130       }
0131       else
0132       {
0133          acc=true;
0134          accelerateFramesNumber--;
0135       }
0136    }
0137    else
0138       rotateFramesNumber--;
0139 
0140 }
0141 
0142 
0143 AiSprite Ai::nextPosition(AiSprite sp,double mult)
0144 {
0145    double abs_2,nx,ny,sq,eg;
0146    if(!sp.sun)
0147    {
0148       abs_2=sp.x*sp.x+sp.y*sp.y;
0149       if(abs_2<1)
0150          abs_2=1;
0151       sq=sqrt(abs_2);
0152       nx=sp.x/sq;
0153       ny=sp.y/sq;
0154       eg=cfg->gravity*mult;
0155       sp.dx-=eg*nx/abs_2;
0156       sp.dy-=eg*ny/abs_2;
0157 
0158       sp.x+=sp.dx*mult;
0159       sp.y+=sp.dy*mult;
0160 
0161       if(sp.x*sp.x+sp.y*sp.y<1600)
0162          sp.sun=true;
0163       else
0164       {
0165              //simple bounds actions
0166          if(sp.x>sfwidth_2)
0167          {
0168             sp.x-=sfwidth;
0169             sp.border=true;
0170          }
0171          else if(sp.x<-sfwidth_2)
0172          {
0173             sp.x+=sfwidth;
0174             sp.border=true;
0175          }
0176          if(sp.y>sfheight_2)
0177          {
0178             sp.y-=sfheight;
0179             sp.border=true;
0180          }
0181          else if(sp.y<-sfheight_2)
0182          {
0183             sp.y+=sfheight;
0184             sp.border=true;
0185          }
0186       }
0187    }
0188 
0189    return sp;
0190 }
0191 
0192 void Ai::nextPositions(const AiSprite &sp,QVector<AiSprite> *a,int frames)
0193 {
0194    int i,num;
0195    double fmult=cfg->gamespeed*frames;
0196 
0197    (*a)[0]=nextPosition(sp,cfg->gamespeed);
0198    num=a->size();
0199    for(i=1;i<num;i++)
0200       (*a)[i]=nextPosition((*a)[i-1],fmult);
0201 }
0202 
0203 void Ai::calculateNextPositions()
0204 {
0205    unsigned int i;
0206    int j;
0207 
0208    j=(int)(calcPositionNumber[Options::aiDifficulty(playerNumber)]/cfg->gamespeed);
0209 
0210    if(shipsNextPositions[0]->size() != j)
0211       for(i=0;i<2;++i)
0212          shipsNextPositions[i]->resize(j);
0213 
0214    for(i=0;i<2;++i)
0215       nextPositions(ship[i]->toAiSprite(),shipsNextPositions[i],
0216                     calcFrameIncrement[Options::aiDifficulty(playerNumber)]);
0217 
0218    if(cfg->maxMines > static_cast<uint>(aiMines[0]->size()))
0219       for(i=0;i<2;++i)
0220          aiMines[i]->resize(cfg->maxMines);
0221 
0222    for(i=0;i<2;++i)
0223    {
0224       for (j=0; j<mines[i]->size(); ++j)
0225       {
0226          (*(aiMines[i]))[j]=mines[i]->value(j)->toAiSprite();
0227       }
0228       mineNumber[i]=j;
0229    }
0230 }
0231 
0232 void Ai::tryShots()
0233 {
0234    AiSprite shot,me;
0235    double rot,nr,nx,ny;
0236    int i,f,frameIncrement,frameNum;
0237    Hit hit;
0238    Shot *goodShot;
0239 
0240    me=ship[playerNumber]->toAiSprite();
0241    rot=ship[playerNumber]->getRotation();
0242 
0243        //Each 'frameIncrement' frames a shot is tried
0244    frameIncrement=(int)((2*M_PI/calcShotDirections[Options::aiDifficulty(playerNumber)])
0245                         /cfg->rotationSpeed);
0246    if(frameIncrement==0)
0247       frameIncrement=1;
0248        //Number of frames needed to rotate 180 degrees
0249    frameNum=(int)(M_PI/(frameIncrement*cfg->rotationSpeed));
0250 
0251        //if too much bullets are on the playfield, no shot is tried
0252    if(bullets[playerNumber]->count() <
0253       (static_cast<int>(cfg->maxBullets) + ship[playerNumber]->getBulletPowerups()))
0254    {
0255       for(f=0;f<=frameNum;++f)
0256       {
0257          if(f!=0)
0258             for(i=0;i<frameIncrement;++i)
0259                me=nextPosition(me,cfg->gamespeed);
0260          else
0261             me=nextPosition(me,cfg->gamespeed);
0262 
0263          if(!ship[playerNumber]->reloadsBullet(f*frameIncrement*cfg->gamespeed))
0264          {
0265             for(i=0;i<2;++i)
0266             {
0267                if((f==0)&&(i==1))
0268                   continue;
0269                if(i==0)
0270                   nr=rot+frameIncrement*f*cfg->rotationSpeed;
0271                else
0272                   nr=rot-frameIncrement*f*cfg->rotationSpeed;
0273 
0274                nx=cos(nr);
0275                ny=sin(nr);
0276                shot.x=me.x+nx*SHOTDIST;
0277                shot.y=me.y+ny*SHOTDIST;
0278                shot.dx=me.dx+nx*cfg->shotSpeed;
0279                shot.dy=me.dy+ny*cfg->shotSpeed;
0280                shot.sun=false;
0281                shot.border=false;
0282 
0283                hit=firstObject(shot,f*frameIncrement,
0284                                calcFrameIncrement[Options::aiDifficulty(playerNumber)]);
0285                if((hit.object!=HNOTHING) &&
0286                   !((hit.object==HSHIP)&&(hit.playerNumber==playerNumber)))
0287                {
0288                   goodShot=new Shot;
0289                   goodShot->hit=hit;
0290                   goodShot->rotation=(i==0?RLEFT:RRIGHT);
0291                   goodShot->rotationFrames=f*frameIncrement;
0292                   goodShot->score=1e10;
0293                   myShots.append(goodShot);
0294                }
0295             }
0296          }
0297       }
0298    }
0299 }
0300 
0301 Hit Ai::firstObject(AiSprite shot,int time,int frames)
0302 {
0303    int optime,i,num,rtime,basetime,t,m;
0304    double dist,distx,disty,shiplastdist=0;
0305    bool shipdistgreater=true,hitfound=false;
0306    Hit hit={HNOTHING,0,0,0,1e10};
0307 
0308    basetime=time/frames;
0309    if((time%frames)>0)
0310       basetime++;
0311    rtime=basetime*frames-time;
0312    optime=shipsNextPositions[0]->size();
0313 
0314    num=optime-basetime;
0315    if(num>0)
0316    {
0317       for(t=0;(t<num)&&(!hitfound)&&(!shot.sun);++t)
0318       {
0319          if(t==0)
0320             shot=nextPosition(shot,cfg->gamespeed*rtime);
0321          else
0322             shot=nextPosition(shot,cfg->gamespeed*frames);
0323 
0324              //distance to other objects
0325          for(i=0;i<2;++i)
0326          {
0327             distx=(*(shipsNextPositions[i]))[basetime].x-shot.x;
0328             disty=(*(shipsNextPositions[i]))[basetime].y-shot.y;
0329             dist=distx*distx+disty*disty;
0330                 //own ship
0331             if(i==playerNumber)
0332             {
0333                if(dist<shiplastdist)
0334                   shipdistgreater=false;
0335                if((!shipdistgreater)&&(dist<hit.distance))
0336                {
0337                   hit.object=HSHIP;
0338                   hit.objectNumber=0;
0339                   hit.playerNumber=i;
0340                   hit.hitTime=basetime*frames;
0341                   hit.distance=dist;
0342                }
0343                shiplastdist=dist;
0344             }
0345                 //other ship
0346             else if(dist<hit.distance)
0347             {
0348                hit.object=HSHIP;
0349                hit.objectNumber=0;
0350                hit.playerNumber=i;
0351                hit.hitTime=basetime*frames;
0352                hit.distance=dist;
0353             }
0354 
0355                 //mines
0356             for(m=0;m<mineNumber[i];++m)
0357             {
0358                distx=(*(aiMines[i]))[m].x-shot.x;
0359                disty=(*(aiMines[i]))[m].y-shot.y;
0360                dist=distx*distx+disty*disty;
0361 
0362                if(dist<hit.distance)
0363                {
0364                   hit.object=HMINE;
0365                   hit.playerNumber=i;
0366                   hit.objectNumber=m;
0367                   hit.hitTime=basetime*frames;
0368                   hit.distance=dist;
0369                }
0370             }
0371          }
0372          if(hit.distance<100)
0373             hitfound=true;
0374          basetime++;
0375       }
0376    }
0377 
0378    return hit;
0379 }
0380 
0381 void Ai::testForHits()
0382 {
0383    AiSprite shot;
0384    int i,j;
0385    int m,p;
0386    BulletSprite *bullet;
0387    Hit *h;
0388    Hit hit;
0389    bool hitfound=false;
0390    double distance,dx,dy;
0391    int listsize; // used for caching QtList::size()
0392 
0393    if(calculateCollisions>0)
0394    {
0395       calculateCollisions--;
0396       i=0;
0397       listsize = objectsHitByShip.size();
0398       while(i<listsize)
0399       {
0400          h = objectsHitByShip[i];
0401          if(h->hitTime>0)
0402          {
0403             h->hitTime--;
0404             i++;
0405          }
0406          else
0407          {
0408             objectsHitByShip.removeAt(i);
0409             delete h;
0410             listsize--;
0411          }
0412       }
0413       i=0;
0414       listsize = minesHitByShot.size();
0415       while(i<listsize)
0416       {
0417          h=minesHitByShot[i];
0418          if(h->hitTime>0)
0419          {
0420             h->hitTime--;
0421             i++;
0422          }
0423          else
0424          {
0425             minesHitByShot.removeAt(i);
0426             delete h;
0427             listsize--;
0428          }
0429       }
0430    }
0431    else
0432    {
0433       qDeleteAll(objectsHitByShip);
0434       objectsHitByShip.clear();
0435       qDeleteAll(minesHitByShot);
0436       minesHitByShot.clear();
0437       for(i=0;i<2;++i)
0438       {
0439          listsize = bullets[i]->size();
0440          for (j=0; j<listsize; ++j)
0441          {
0442             bullet=bullets[i]->value(j);
0443             shot=bullet->toAiSprite();
0444             hit=firstObject(shot,0,calcFrameIncrement[Options::aiDifficulty(playerNumber)]);
0445             if(hit.object==HMINE)
0446             {
0447                h=new Hit(hit);
0448                minesHitByShot.append(h);
0449             }
0450             if((hit.object==HSHIP)&&(hit.playerNumber==playerNumber))
0451             {
0452                h=new Hit(hit);
0453                h->object=HSHOT;
0454                objectsHitByShip.append(h);
0455             }
0456          }
0457       }
0458 
0459       hit.object=HNOTHING;
0460       hit.distance=400;
0461 
0462       for(i=0;(i<shipsNextPositions[0]->size()) &&
0463              !(*shipsNextPositions[playerNumber])[i].sun;++i)
0464       {
0465          if((borderTime<0) && (*shipsNextPositions[playerNumber])[i].border)
0466             borderTime=i*calcFrameIncrement[Options::aiDifficulty(playerNumber)];
0467 
0468          dx=(*shipsNextPositions[playerNumber])[i].x;
0469          dy=(*shipsNextPositions[playerNumber])[i].y;
0470          distance=dx*dx+dy*dy;
0471          if((distance<3025)&&(sunTime<0))
0472             sunTime=i*calcFrameIncrement[Options::aiDifficulty(playerNumber)];
0473 
0474          if(!hitfound)
0475             for(p=0;p<2;++p)
0476                for(m=0;m<mineNumber[p];++m)
0477                {
0478                   dx=(*shipsNextPositions[playerNumber])[i].x-(*aiMines[p])[m].x;
0479                   dy=(*shipsNextPositions[playerNumber])[i].y-(*aiMines[p])[m].y;
0480                   distance=dx*dx+dy*dy;
0481                   if(hit.distance>distance)
0482                   {
0483                      hit.object=HMINE;
0484                      hit.playerNumber=p;
0485                      hit.objectNumber=m;
0486                      hit.hitTime=i*calcFrameIncrement[Options::aiDifficulty(playerNumber)];
0487                      hit.distance=distance;
0488                      if(distance<100)
0489                         hitfound=true;
0490                   }
0491                }
0492       }
0493       if(hit.object!=HNOTHING)
0494       {
0495          h=new Hit(hit);
0496          objectsHitByShip.append(h);
0497       }
0498       calculateCollisions=(int)(calcCollisions[Options::aiDifficulty(playerNumber)]/cfg->gamespeed);
0499    }
0500 }
0501 
0502 void Ai::shotScores()
0503 {
0504    Shot *s;
0505    Hit *h,*mh;
0506    bool found,foundmh;
0507    double dist,dx,dy,fuel;
0508    int i,j,k;
0509    int listsize,listsize2; // used for caching QtList::size()
0510 
0511 
0512    dx=(*shipsNextPositions[playerNumber])[0].x-(*shipsNextPositions[opponentNumber])[0].x;
0513    dy=(*shipsNextPositions[playerNumber])[0].y-(*shipsNextPositions[opponentNumber])[0].y;
0514    dist=dx*dx+dy*dy;
0515 
0516    listsize = myShots.size();
0517    for (j=0; j<listsize; ++j)
0518    {
0519       s = myShots[j];
0520       fuel=(100-(ship[playerNumber]->getEnergy()-cfg->shotEnergyNeed));
0521       s->score=fuel*fuel/10 + s->hit.distance+s->hit.hitTime;
0522       if(dist > (75*75))
0523          s->score+=waitShot*8;
0524       else
0525          s->score+=waitShot*4;
0526 
0527       if(s->hit.object==HMINE)
0528       {
0529          found=false;
0530          for (i=0; i<objectsHitByShip.size() && !found; ++i)
0531          {
0532             h=objectsHitByShip[i];
0533             if((h->object==HMINE)&&(h->playerNumber==s->hit.playerNumber)
0534                &&(h->objectNumber==s->hit.objectNumber))
0535                    //ship will hit a mine that will be hitten by the shot
0536             {
0537                found=true;
0538                    //ship hits earlier than shot
0539                if(h->hitTime<s->hit.hitTime)
0540                   s->score+=1000;
0541                else
0542                {
0543                   foundmh=false;
0544                   listsize2 = minesHitByShot.size();
0545                   for (k=0; k<listsize2 && !foundmh; ++k)
0546                   {
0547                      mh = minesHitByShot[k];
0548                      if((mh->playerNumber==s->hit.playerNumber)
0549                         &&(mh->objectNumber==s->hit.objectNumber))
0550                             //another shot will hit the mine
0551                      {
0552                         /* FIXME: check (and understand) this function
0553                            original version: "found" in for-clause, bot was never true
0554                            foundmh set to false before but never changed */
0555                         foundmh = true;
0556                         if(mh->hitTime<s->hit.hitTime)
0557                            s->score+=500;
0558                         else
0559                            s->score-=300;
0560                      }
0561                   }
0562                }
0563             }
0564          }
0565          if(!found)
0566             s->score+=1000;
0567       }
0568    }
0569 }
0570 
0571 void Ai::chooseAction()
0572 {
0573    double bestScore=1e10;
0574    Shot *bestShot = nullptr,*s;
0575    AiSprite actualpos;
0576    double posangle,movephi,phiright,phileft,torotate=0,velangle;
0577    int framesleft,framesright;
0578    bool rotateAndAccelerate=false;
0579    Hit *nextHit = nullptr;
0580    int i;
0581 
0582 //   int shotHitTime=1000000;
0583    nextHit = nullptr;
0584 /*   for(h=objectsHitByShip.first();h;h=objectsHitByShip.next())
0585       if(h->object==HSHOT)
0586          if(h->hitTime<shotHitTime)
0587          {
0588             nextHit=h;
0589             shotHitTime=h->hitTime;
0590             }*/
0591    if((borderTime>0) || (sunTime>0) || (nextHit))
0592    {
0593       actualpos=ship[playerNumber]->toAiSprite();
0594       posangle=rectToAngle(actualpos.x,actualpos.y);
0595 
0596       movephi=rectToAngle((*shipsNextPositions[playerNumber])[0].x,
0597                           (*shipsNextPositions[playerNumber])[0].y) - posangle;
0598 
0599       phileft=movephi+cfg->rotationSpeed;
0600       phiright=movephi-cfg->rotationSpeed;
0601 
0602       if((borderTime>0)&& !((sunTime>0)&&(sunTime<borderTime)))
0603       {
0604          bestScore=borderTime/cfg->gamespeed;
0605          if(score>bestScore)
0606          {
0607             velangle=rectToAngle(actualpos.dx,actualpos.dy);
0608             if(fabs(difference(posangle+3*M_PI/4,velangle))
0609                < fabs(difference(posangle-3*M_PI/4,velangle)))
0610                torotate=posangle-3*M_PI/4-ship[playerNumber]->getRotation();
0611             else
0612                torotate=posangle+3*M_PI/4-ship[playerNumber]->getRotation();
0613             rotateAndAccelerate=true;
0614             score=bestScore;
0615             accelerateFramesNumber=(int)(8/cfg->gamespeed);
0616          }
0617       }
0618       else if(sunTime>0)
0619       {
0620          bestScore=sunTime/(cfg->gamespeed*10)
0621             +(actualpos.x*actualpos.x+actualpos.y*actualpos.y)/5000;
0622          if(score>bestScore)
0623          {
0624             velangle=rectToAngle(actualpos.dx,actualpos.dy);
0625             if(fabs(difference(posangle+2*M_PI/5,velangle))
0626                < fabs(difference(posangle-2*M_PI/5,velangle)))
0627                torotate=posangle+2*M_PI/5-ship[playerNumber]->getRotation();
0628             else
0629                torotate=posangle-2*M_PI/5-ship[playerNumber]->getRotation();
0630             rotateAndAccelerate=true;
0631             score=bestScore;
0632             accelerateFramesNumber=(int)(8/cfg->gamespeed);
0633          }
0634       }
0635       else
0636       {
0637 /*         bestScore=abs(nextHit->hitTime-90)*4/cfg->gamespeed + nextHit->distance*2
0638             + (100-(ship[playerNumber]->getEnergy()-cfg->shotEnergyNeed))*4;
0639          if((score>bestScore)&&(bestScore<400))
0640          {
0641             velangle=rectToAngle(actualpos.dx,actualpos.dy);
0642             if(fabs(difference(posangle+2*M_PI/5,velangle))
0643                < fabs(difference(posangle-2*M_PI/5,velangle)))
0644                torotate=posangle+2*M_PI/5-ship[playerNumber]->getRotation();
0645             else
0646                torotate=posangle-2*M_PI/5-ship[playerNumber]->getRotation();
0647             rotateAndAccelerate=true;
0648             score=bestScore;
0649             accelerateFramesNumber=(int)(4/cfg->gamespeed);
0650             }*/
0651       }
0652 
0653       if(rotateAndAccelerate)
0654       {
0655          if(phileft<0)
0656             framesleft=1000;
0657          else
0658          {
0659             while(torotate<0)
0660                torotate+=2*M_PI;
0661             while(torotate>=2*M_PI)
0662                torotate-=2*M_PI;
0663             framesleft=(int)(torotate/phileft+0.5);
0664          }
0665 
0666          if(phiright>0)
0667             framesright=1000;
0668          else
0669          {
0670             while(torotate>0)
0671                torotate-=2*M_PI;
0672             while(torotate<=-2*M_PI)
0673                torotate+=2*M_PI;
0674             framesright=(int)(torotate/phiright+0.5);
0675          }
0676 
0677          if(framesright<framesleft)
0678          {
0679             rotation=RRIGHT;
0680             rotateFramesNumber=framesright;
0681          }
0682          else
0683          {
0684             rotation=RLEFT;
0685             rotateFramesNumber=framesleft;
0686          }
0687          shoot=false;
0688 
0689       }
0690    }
0691    else
0692    {
0693       int listsize; // used for caching QtList::size()
0694       bestShot = nullptr;
0695       listsize = myShots.size();
0696       for (i=0; i<listsize; ++i)
0697       {
0698          s=myShots[i];
0699          if(s->score<bestScore)
0700          {
0701             bestScore=s->score;
0702             bestShot=s;
0703          }
0704       }
0705       if(bestShot)
0706       {
0707          if((bestScore<score)&&(bestScore<400))
0708          {
0709             rotation=bestShot->rotation;
0710             rotateFramesNumber=bestShot->rotationFrames;
0711             accelerateFramesNumber=0;
0712             shoot=true;
0713             score=bestScore;
0714             calculateCollisions = 0;
0715             waitShot=(int) rint( random.bounded(1.0) *
0716                              calcNextShot[Options::aiDifficulty(playerNumber)]
0717                                  /cfg->gamespeed);
0718          }
0719       }
0720    }
0721 }
0722 
0723 void Ai::setSpriteFieldSize()
0724 {
0725    sfwidth=(double)(ship[playerNumber]->spriteFieldWidth());
0726    sfheight=(double)(ship[playerNumber]->spriteFieldHeight());
0727    sfwidth_2=sfwidth/2.0;
0728    sfheight_2=sfheight/2.0;
0729 }
0730