home *** CD-ROM | disk | FTP | other *** search
/ WarCraft 2000 - Nuclear Epidemic / W2000.nrg / SOURCE.War2000 / Crowd.cpp < prev    next >
C/C++ Source or Header  |  1998-08-24  |  10KB  |  455 lines

  1. #include "ddini.h"
  2. #include "ResFile.h"
  3. #include "FastDraw.h"
  4. #include "mgraph.h"
  5. #include "mouse.h"
  6. #include "menu.h"
  7. #include "MapDiscr.h"
  8. #include "multipl.h"
  9. #include "fog.h"
  10. #include "walls.h"
  11. #include "Nature.h"
  12. #include "Nucl.h"
  13. #include "TopZones.h"
  14. #include "Megapolis.h"
  15. #include <math.h>
  16. extern int DHAPROB;
  17. extern int DRECLPROB;
  18. extern int DDIVPROB;
  19. extern int HANSWPROB;
  20. extern int HREQRADIUS;
  21. extern int CROWDMIN;
  22. extern int HCPROB;
  23. extern int CMC1;
  24. extern int CMC2;
  25. extern int CMC3;
  26. word FindEnemyInCell(int x,int y,byte NI,byte Kind){
  27.     int xx=(x<<2);
  28.     int yy=(y<<2);
  29.     OneObject* OB;
  30.     word MID;
  31.     for(int dx=0;dx<4;dx++)
  32.         for(int dy=0;dy<4;dy++){
  33.             MID=Mops[yy+dy][xx+dx];
  34.             if(MID!=0xFFFF){
  35.                 OB=Group[MID];
  36.                 if(OB&&OB->NNUM==NI&&OB->Kind==Kind){
  37.                     Order1* OR1=OB->LocalOrder;
  38.                     if(!int(OR1)||(OR1&&OR1->OrderType!=89))return MID;
  39.                 };
  40.             };
  41.         };
  42.     return 0xFFFF;
  43. };
  44. word FindEnemy(int x,int y,byte NI){
  45.     int sx=x>>2;
  46.     int sy=y>>2;
  47.     int sx1=sx;
  48.     int sy1=sy;
  49.     int r=3;
  50.     do{
  51.         for(int x1=sx;x1<=sx1;x1++)
  52.             for(int y1=sy;y1<=sy1;y1++){
  53.                 if(x1==sx||x1==sx1||y1==sy||y1==sy1){
  54.                     Cell8x8* CL=&TCInf[NI][y1][x1];
  55.                     if(CL->Towers>0){
  56.                         word PS=FindEnemyInCell(x1,y1,NI,1);
  57.                         if(PS!=0xFFFF)return PS;
  58.                     };
  59.                     if(CL->Buildings>0){
  60.                         word PS=FindEnemyInCell(x1,y1,NI,4);
  61.                         if(PS!=0xFFFF)return PS;
  62.                     };
  63.                     if(CL->Peasants>0){
  64.                         word PS=FindEnemyInCell(x1,y1,NI,0);
  65.                         if(PS!=0xFFFF)return PS;
  66.                     };
  67.                     if(CL->Warriors>0){
  68.                         word PS=FindEnemyInCell(x1,y1,NI,2);
  69.                         if(PS!=0xFFFF)return PS;
  70.                     };
  71.                 };
  72.             };
  73.         sx1++;
  74.         sy1++;
  75.         sx--;
  76.         sy--;
  77.         if(sx<0)sx=0;
  78.         if(sy<0)sy=0;
  79.         if(sx1>63)sx1=63;
  80.         if(sy1>63)sy1=63;
  81.         r--;
  82.     }while(r);
  83.     return 0xFFFF;
  84. };
  85. int Crowd::Funct(int x,int y,int Lx,int Ly){
  86.     if(x<0||x+Lx>63||y<0||y+Ly>63)return 10000000;
  87.     int NL=0;
  88.     for(int dx=0;dx<Lx;dx++)
  89.         for(int dy=0;dy<Ly;dy++)
  90.             NL+=NLocks[y+dy][x+dx];
  91.     NL=CMC1*NL;
  92.     int DX=x+((Lx-BestLx)>>1)-BestX;
  93.     int DY=y+((Ly-BestLy)>>1)-BestY;
  94.     int AM=DX*DX+DY*DY;
  95.     int HH=(DX*LastDx+DY*LastDy);
  96.     int ADDO;
  97.     if(AM!=0&&LastAbs!=0){
  98.         ADDO=div(HH*HH*CMC2,AM*LastAbs).quot;
  99.         if(HH<0)ADDO=-ADDO;
  100.         NL-=ADDO;
  101.     };
  102.  
  103.     DX=abs(DX);
  104.     DY=abs(DY);
  105.     if(DY>DX)DX=DY;
  106.     NL+=CMC3*abs(DX);
  107.     //NL+=rando()&15;
  108.     NL+=(int(sqrt((x-DestX)*(x-DestX)+(y-DestY)*(y-DestY)))<<3);
  109.     return NL;
  110. };
  111. void Crowd::GetSize(){
  112.     word MID;
  113.     OneObject* OB;
  114.     int minx=64;
  115.     int miny=64;
  116.     int maxx=0;
  117.     int maxy=0;
  118.     NInside=0;
  119.     NMembers=0;
  120.     for(int i=0;i<MLSize;i++){
  121.         MID=MemList[i];
  122.         if(MID!=0xFFFF){
  123.             OB=Group[MID];
  124.             if(OB&&OB->CrowdRef==this){
  125.                 int xx=OB->x>>2;
  126.                 int yy=OB->y>>2;
  127.                 if(xx>maxx)maxx=xx;
  128.                 if(yy>maxy)maxy=yy;
  129.                 if(xx<minx)minx=xx;
  130.                 if(yy<miny)miny=yy;
  131.                 //if(xx>=BestX&&xx<BestX1&&yy>=BestY&&yy<BestY1)NInside++;
  132.                 if(!OB->LocalOrder)NInside++;
  133.                 NMembers++;
  134.             }else MemList[i]=0xFFFF;
  135.         };
  136.     };
  137.     RealX=minx;
  138.     RealY=miny;
  139.     RealLx=maxx-minx+1;
  140.     RealLy=maxy-miny+1;
  141.     RealX1=maxx;
  142.     RealY1=maxy;
  143. };
  144. void Crowd::FindNewPosition(){
  145.     int BLX=int(sqrt(NMembers))+1;
  146.     int BLX4=BLX>>2;
  147.     if(BLX&3)BLX4++;
  148.     int mx=(msx>>2)-BLX4;
  149.     int my=(msy>>2)-BLX4;
  150.     int sum=1000000;
  151.     int BX=0;
  152.     int BY=0;
  153.     for(int i=0;i<=mx;i++)
  154.         for(int j=0;j<my;j++){
  155.             int FN=Funct(i,j,BLX4,BLX4);
  156.             if(FN<sum){
  157.                 BX=i;
  158.                 BY=j;
  159.                 sum=FN;
  160.             };
  161.         };
  162.     LastDx=BX-BestX;
  163.     LastDy=BY-BestY;
  164.     LastAbs=LastDx*LastDx+LastDy*LastDy;
  165.     BestX=BX;
  166.     BestY=BY;
  167.     BestLx=BLX4;
  168.     BestLy=BLX4;
  169.     BestX1=BX+BLX4-1;
  170.     BestY1=BY+BLX4-1;
  171.     FUNC=sum;
  172. };
  173. void Crowd::SendCrowd(){
  174.     int x=(BestX<<2)+(BestLx<<1);
  175.     int y=(BestY<<2)+(BestLy<<1);
  176.     int RNSel=0;
  177.     word Nsel=MLSize;
  178.     word* SMon=MemList;
  179.     if(!Nsel)return;
  180.     word MID;
  181.     for(int k=0;k<Nsel;k++){
  182.         MID=SMon[k];
  183.         if(MID!=0xFFFF&&int(Group[MID])){
  184.             SMon[RNSel]=SMon[k];
  185.             RNSel++;
  186.         };
  187.     };
  188.     Nsel=RNSel;
  189.     MLSize=Nsel;
  190.     if(!Nsel)return;
  191.     int Sqs=int(sqrt(Nsel));
  192.     int Glx=Sqs;
  193.     int Gly=Sqs;
  194.     if(Glx*Gly>Nsel)Glx--;
  195.     if(Glx*Gly<Nsel)Glx++;else{
  196.         if(Glx*Gly>Nsel)Gly--;
  197.         if(Glx*Gly<Nsel)Gly++;
  198.     };
  199.     int gx1=x-(Glx>>1);
  200.     int gy1=y-(Gly>>1);
  201.     if(gx1<=0)gx1=1;
  202.     if(gy1<=0)gy1=1;
  203.     if(gx1+Glx>msx)gx1=msx-Glx+1;
  204.     if(gy1+Gly>msy)gy1=msy-Gly+1;
  205.     int zx=gx1;
  206.     int zy=gy1;
  207.     for(int i=0;i<Nsel;i++){
  208.         if(zx-gx1+1>Glx){zx=gx1;zy++;};
  209.         MID=SMon[i];
  210.         if(MID!=0xFFFF&&int(Group[MID]))
  211.             Group[SMon[i]]->SendTo(zx,zy,0);
  212.         zx++;
  213.     };
  214. };
  215. void Crowd::CreateCrowd(byte N){
  216.     //int Best=BestNat;
  217.     //if(NI==BestNat){
  218.     //    Best=NextBest;
  219.     //};
  220.     //if(Best<0||Best>8)return;
  221.     word MLS[1024];
  222.     word NMem=0;
  223.     word MID;
  224.     NI=N;
  225.     Usage=1;
  226.     OneObject* OB;
  227.     for(int i=1;i<msy;i++){
  228.         for(int j=0;j<msx;j++){
  229.             MID=Mops[i][j];
  230.             if(MID!=0xFFFF){
  231.                 OB=Group[MID];
  232.                 if(OB&&OB->NNUM==NI&&(!OB->CrowdRef)&&OB->Kind==2&&NMem<1023){
  233.                     MLS[NMem]=MID;
  234.                     NMem++;
  235.                     //OB->CrowdRef=this;
  236.                 };
  237.             };
  238.         };
  239.     };
  240.     for(i=0;i<32;i++)ForAtt[i]=0xFFFF;
  241.     if(NMem>CROWDMIN){
  242.         Active=true;
  243.         MLSize=NMem;
  244.         if(MemList)free(MemList);
  245.         MemList=new word[MLSize];
  246.         memcpy(MemList,MLS,MLSize<<1);
  247.         for(i=0;i<NMem;i++){
  248.             MID=MLS[i];
  249.             OB=Group[MID];
  250.             if(OB)OB->CrowdRef=this;
  251.         };
  252.         LastDx=int(rando())&7-3;
  253.         LastDy=int(rando())&7-3;
  254.         GetSize();
  255.         int BLX=int(sqrt(NMembers))+1;
  256.         int BLX4=BLX>>2;
  257.         if(BLX&3)BLX4++;
  258.         BestX=RealX+((RealLx-BestLx)>>1);
  259.         BestY=RealY+((RealLy-BestLy)>>1);
  260.         BestLx=BLX4;
  261.         BestLy=BLX4;
  262.         BestX1=BestX+BestLx-1;
  263.         BestY1=BestY+BestLy-1;
  264.         Forces* FR=&NForces[0];
  265.         if(FR->NBuild){
  266.             DestX=(FR->CenterX)>>2;
  267.             DestY=(FR->CenterY)>>2;
  268.         }else{
  269.             DestX=msx>>3;
  270.             DestY=msy>>3;
  271.         };
  272.     };
  273. };
  274. void Crowd::HandleCrowd(){
  275.     if(Active&&!(rando()<HCPROB)){
  276.         GetSize();
  277.         if(!HandleAttacks(1)){
  278.             if(NMembers<2)
  279.                 Disband();
  280.             if(NInside+(NInside>>3)>=NMembers){
  281.                 FindNewPosition();
  282.                 SendCrowd();
  283.             };
  284.         };
  285.     };
  286. };
  287. void Crowd::HandleDefence(){
  288. word MID,MID1;
  289.     OneObject *OB,*US;
  290.     bool ChkFar=false;;
  291.     Forces* FR=&NForces[NI];
  292.     int minx,miny,maxx,maxy,xu,yu,dst;
  293.     if(FR->NBuild){
  294.         minx=FR->MinX;
  295.         miny=FR->MinY;
  296.         maxx=FR->MaxX;
  297.         maxy=FR->MaxY;
  298.         ChkFar=true;
  299.     };
  300.     bool Present=false;
  301.     for(int kk=0;kk<32;kk++)if(ForAtt[kk]!=0xFFFF)return;
  302.     for(kk=0;kk<MLSize;kk++){
  303.         MID=MemList[kk];
  304.         if(MID!=0xFFFF){
  305.             OB=Group[MID];
  306.             if(OB){
  307.                 int xx=OB->x>>2;
  308.                 int yy=OB->y>>2;
  309.                 Cell8x8* CC=&TCInf[NI][yy][xx];
  310.                 if(CC->Farms||CC->Buildings||CC->Towers||CC->Peasants)OB->MoveFrom(0);
  311.                 if(ChkFar){
  312.                     xu=OB->x;
  313.                     yu=OB->y;
  314.                     if(xu>maxx)xu=maxx;
  315.                     if(yu>maxy)yu=maxy;
  316.                     if(xu<minx)xu=minx;
  317.                     if(yu<miny)yu=miny;
  318.                     dst=OB->DistTo(xu,yu);
  319.                     if(dst>6&&!OB->LocalOrder)OB->SendTo(xu,yu,1);
  320.                     if(dst>15){
  321.                         if(!OB->Attack){
  322.                             OB->SendTo(xu,yu,1);
  323.                         }else{
  324.                             if(OB->EnemyDist>12){
  325.                             OB->SendTo(xu,yu,129);
  326.                             };
  327.                         };
  328.                     };
  329.                 };
  330.             };
  331.         };
  332.     };
  333. };
  334. void Crowd::Disband(){
  335.     word MID;
  336.     OneObject* OB;
  337.     for(int i=0;i<MLSize;i++){
  338.         MID=MemList[i];
  339.         if(MID!=0xFFFF){
  340.             OB=Group[MID];
  341.             if(OB&&OB->CrowdRef==this)OB->CrowdRef=NULL;
  342.         };
  343.         MemList[i]=0xFFFF;
  344.     };
  345.     Active=false;
  346. };
  347. bool Crowd::DisbandHalf(){
  348.     word MID;
  349.     OneObject* OB;
  350.     Nation* NT=&NATIONS[NI];
  351.     int NBusy=NT->NFarms*4;
  352.     if(NBusy>50)NBusy=50;
  353.     int NAtt=NT->NFarms*3;
  354.     if(NBusy+NAtt>MLSize)return false;
  355.     NAtt=MLSize-NBusy;
  356.     for(int i=0;i<NAtt;i++){
  357.         MID=MemList[i];
  358.         if(MID!=0xFFFF){
  359.             OB=Group[MID];
  360.             if(OB&&OB->CrowdRef==this)OB->CrowdRef=NULL;
  361.             MemList[i]=0xFFFF;
  362.         };
  363.     };
  364.     return true;
  365. };
  366. Crowd::Crowd(){
  367.     Active=false;
  368.     for(int i=0;i<32;i++)ForAtt[i]=0xFFFF;
  369.     MemList=NULL;
  370. };
  371. void Crowd::AddToAttackQueue(word ID){
  372.     for(int i=0;i<32;i++){
  373.         if(ID==ForAtt[i])return;
  374.     };
  375.     for(i=0;i<32;i++){
  376.         if(ForAtt[i]==0xFFFF){
  377.             ForAtt[i]=ID;
  378.             return;
  379.         };
  380.     };
  381.     ForAtt[rando()&31]=ID;
  382. };
  383. /*bool Crowd::AddToCrowd(word ID){
  384.     OneObject* OB=Group[ID];
  385.     if(OB->NNUM!=NI)return;
  386.     if(OB->CrowdRef)return;
  387.     for(int i=0;i<MLSize;i++){
  388.         if(MemList[i]==0xFFFF){
  389.             MemList[i]=ID;
  390.             OB->CrowdRef=this;
  391.         };
  392.     };
  393. };*/
  394. bool Crowd::HandleAttacks(byte Prio){
  395.     word MID,MID1;
  396.     OneObject *OB,*US;
  397.     Nation* NATT=&NATIONS[NI];
  398.     bool Present=false;
  399.     int kk=rando()&31;
  400.     byte MyMsk=1<<NI;
  401.     MID=ForAtt[kk];
  402.     if(MID!=0xFFFF){
  403.         OB=Group[MID];
  404.         if(OB){
  405.             kk=FindEnemy(OB->x,OB->y,OB->NNUM);
  406.             if(kk!=0xFFFF)AddToAttackQueue(kk);
  407.         };
  408.     };
  409.     for(int i=0;i<32;i++){
  410.         MID=ForAtt[i];
  411.         if(MID!=0xFFFF){
  412.             OB=Group[MID];
  413.             if(OB&&(!(OB->NMask&MyMsk))&&!OB->Sdoxlo){
  414.                 Present=true;
  415.                 int mind=2000;
  416.                 int cxd=0;
  417.                 for(int j=0;j<MLSize;j++){
  418.                     MID1=MemList[j];
  419.                     if(MID1!=0xFFFF){
  420.                         US=Group[MID1];
  421.                         if(US){
  422.                             if(US->Magic>60&&(!NATT->MagicDelay)&&US->DistTo(OB->x,OB->y)<12){
  423.                                 bool MagDone=false;
  424.                                     GeneralObject* UGO=US->Ref.General;
  425.                                     word ms=1;
  426.                                     for(int qq=0;qq<UGO->NWeap;qq++){
  427.                                         if(rando()<8192&&UGO->MagAgainst&ms){
  428.                                             byte swi=UGO->SWPIndex[qq];
  429.                                             if(swi!=255){
  430.                                                 SWPAR* SWX=&NATT->SWP[swi];
  431.                                                 if(SWX&&SWX->Enabled&&US->Magic>SWX->MinMagic){
  432.                                                     //Do them all!
  433.                                                     US->ComplexAttack(OB->Index,qq,16);
  434.                                                     MagDone=true;
  435.                                                     NATT->MagicDelay=4;
  436.                                                 };
  437.                                             };
  438.                                         };
  439.                                         ms=ms<<1;
  440.                                     };
  441.                                     if(!MagDone)US->AttackObj(MID,Prio);
  442.                             }else{
  443.                                 US->AttackObj(MID,Prio);
  444.                             };
  445.                             cxd=US->DistTo(OB->x,OB->y);
  446.                             if(cxd<mind)mind=cxd;
  447.                         };
  448.                     };
  449.                 };
  450.                 if(mind>30)ForAtt[i]=0xFFFF;
  451.             }else ForAtt[i]=0xFFFF;
  452.         };
  453.     };
  454.     return Present;
  455. };