File indexing completed on 2024-04-21 04:04:55
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 <QList> 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 QList<AiSprite> 0038 ((int)(calcPositionNumber[Options::aiDifficulty(playerNumber)]/cfg->gamespeed)); 0039 aiMines[i]=new QList<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,QList<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