0001 //
0002 // Forwards/Main-Classes
0003 //
0004 CTask *ant_task=Fs;
0005 extern class CAnt;
0006 #define WORKER_COST 25
0007 #define QUEEN_COST 150
0008 
0009 class CAIWant {
0010   I32 x,y;
0011   I32 x2,y2;
0012   F64 score;
0013   F64 food_cost;
0014   F64 dirt_cost;
0015   F64 ant_cost;
0016   F64 time_cost;
0017 };
0018 class CAIRequest {
0019   CAIWant *(*fun_ptr)(U8 *colony,CAIRequest*);
0020   I32 x,y;
0021   I32 x2,y2;
0022   I64 user_data;
0023 };
0024 class CAntCluster:CQue {
0025   I64 cx,cy;
0026   I64 cnt;
0027   CAnt *body[0];
0028 }
0029 #define LOCKf_AI_LOCK 1
0030 class CAntColony:CQue {
0031   I64 locks;
0032   I64 food;
0033   I64 dirt;
0034   I64 color;
0035   CD2I64 colony_center;
0036   CQue ants;
0037   CQue commands;
0038   CQue ai_wants;
0039   CAntCluster **clusters;
0040   I64 cluster_cnt;  
0041   U8 *ai_data;
0042   Bool player;
0043 } *player_colony;
0044 //These are put in colony.commands
0045 class CItem:CQue {
0046   U64 ident;
0047   U8 *spr;
0048   CD2I64 position;
0049   I64 user_data;
0050 };
0051 class CAntCommand:CQue {
0052   U64 type;
0053   CItem *follow_item;
0054   CAnt *follow_ant;
0055   I64 x,y;
0056   U8 *spr;
0057 //Private
0058   //When we insert multiple of them make sure we have released the mouse button before we remove commands
0059   F64 insert_tS;
0060 };
0061 extern U0 WorkerAntAITask(CAnt *ant);
0062 class CAnt:CQue {
0063   CAntColony *colony;
0064   CD2I64 position,wander_towards;
0065   F64 distance;
0066   CItem *carry;
0067   I64 steps_to_walk;
0068   I64 direction,tile_x,tile_y;
0069   U8 *sprite;
0070   U8 *sprite2; //alternate animation sprite
0071   F64 rot,fall_speed;
0072   I64 color;
0073   I32 reflectx,reflecty;
0074   CTask *ai_task;
0075   Bool is_queen,going_left,return_to_queen,pad[5];
0076 //private;
0077   CQue ai_commands; //CAntCommand,players should put the sauce in colony->commands
0078   CDC *nav_visited_dc;
0079 };
0080 class CWorker:CAnt {
0081 };
0082 extern U0 CommandControls(I64 m,I64 a1,I64 a2);
0083 extern CItem *NewPieItem(I64 x,I64 y);
0084 extern CItem *NewMelonItem(I64 x,I64 y);
0085 extern CItem *ItemAtPos(I64 x,I64 y);
0086 extern Bool ValidateItem(CItem *val);
0087 extern U0 GenAntClusters(CAntColony *colony); //Generates the ->clusters member,call on world update
0088 extern CAntCluster **GetAntClusters(CAntColony *c,I64 *cnt);
0089 #define WORLD_DIRT1 YELLOW
0090 #define WORLD_DIRT2 BROWN
0091 
0092 #define WORLD_GRASS1 GREEN
0093 #define WORLD_GRASS2 LTGREEN
0094 
0095 
0096 #define WORLD_WATER1 BLUE
0097 #define WORLD_WATER2 CYAN
0098 #define WORLD_WATER3 LTBLUE
0099 #define WORLD_WATER4 LTCYAN
0100 
0101 #define WORLD_ROCK1 DKGRAY
0102 #define WORLD_ROCK2 LTGRAY
0103 #define WORLD_BLACK BLACK
0104 
0105 //These are items not world blocks
0106 #define WORLD_FOOD1 PURPLE
0107 #define WORLD_FOOD2 LTPURPLE
0108 
0109 
0110 
0111 class CWorld {
0112 //See the WORLD_XXX macros
0113   CDC *bitmap;
0114   CQue colonies;
0115   CQue items;
0116   F64 start_tS;
0117 //Camera
0118   F64 cam_zoom;
0119   I64 cam_x,cam_y;
0120 } world;
0121 //
0122 // UI
0123 //
0124 #define COUNTER_W 100
0125 #define COUNTER_H 75
0126 
0127 //
0128 // Counter
0129 //
0130 class CCounterCtrl:CCtrl {
0131   U8 *icon_sprite;
0132   U8 *title;
0133   I64 *cnt;
0134 };
0135 
0136 
0137 //Avoids nerfarios flood filling of background
0138 CDC *Sprite2DCMat4x4B(U8 *spr,I64 *mat,CD2I64 *center=NULL,I64 color=BLACK) {
0139   CDC *space_dc=DCNew(I32_MAX,I32_MAX,Fs,TRUE),*dc;
0140   I64 nul=0;
0141   DCExtentsInit(space_dc);
0142   Sprite3Mat4x4B(space_dc,I32_MAX/2,I32_MAX/2,0,spr,mat);
0143   dc=DCNew(
0144         (space_dc->max_x-space_dc->min_x+7)&~7,
0145         (space_dc->max_y-space_dc->min_y+7)&~7);
0146   DCFill(dc);
0147   dc->color=color;
0148   Sprite3Mat4x4B(dc,-(space_dc->min_x-I32_MAX/2),-(space_dc->min_y-I32_MAX/2),0,spr,mat);
0149   if(center) {
0150     center->x=0;
0151     center->y=0;
0152     Mat4x4MulXYZ(mat,&center->x,&center->y,&nul);
0153     center->x-=space_dc->min_x-I32_MAX/2;
0154     center->y-=space_dc->min_y-I32_MAX/2;
0155   }
0156   DCDel(space_dc);
0157   return dc;
0158 }
0159 
0160 U0 CounterDraw(CDC *dc,CCounterCtrl *cnt) {
0161   U8*title=MStrPrint("%s:%d",cnt->title,*cnt->cnt);
0162   U8 *spr;
0163   CDC *dummy;
0164   I64 minx,miny,maxx,maxy,w,h;
0165   dc->color=BLACK;
0166   GrRect(dc,cnt->left,cnt->top,COUNTER_W,COUNTER_H);
0167   dc->color=YELLOW;
0168   dc->thick=2;
0169   GrBorder(dc,cnt->left+4,cnt->top+4,cnt->left+COUNTER_W-4,cnt->top+COUNTER_H-4);
0170   dc->color=WHITE;
0171   GrPutS(dc,cnt->left+COUNTER_W/2-StrLen(title)*FONT_WIDTH/2.,cnt->top+FONT_HEIGHT+2,title);
0172   if(spr=cnt->icon_sprite) {
0173     SpriteExtents(spr,&minx,&maxx,&miny,&maxy);
0174     w=maxx-minx;
0175     h=maxy-miny;
0176 //AVOID FLOOD FILLS MAKING STUFF STANGE
0177     dummy=DCNew(w,h);
0178     DCFill(dummy,TRANSPARENT);
0179     Sprite3(dummy,-minx,-miny,0,spr);
0180     GrBlot(dc,cnt->left+COUNTER_W/2-w/2,cnt->top+COUNTER_H/2-h/2,dummy);
0181     DCDel(dummy);
0182   }
0183   Free(title);
0184 }
0185 
0186 
0187 
0188 
0189 U0 CounterUpdateVals(CCtrl *cc) {
0190 CTask *t=cc->win_task;
0191 cc->top=t->pix_height-COUNTER_H;
0192 cc->bottom=t->pix_height;
0193 cc->right=cc->left+COUNTER_W;
0194 }
0195 CCounterCtrl *CounterNew(U8 *title,U8 *sprite,I64 x,I64 *to) {
0196   CCounterCtrl *new=CAlloc(sizeof CCounterCtrl);
0197   new->flags=CTRLF_SHOW;
0198   new->win_task=Fs;
0199   new->update_derived_vals=&CounterUpdateVals;
0200   new->draw_it=&CounterDraw;
0201   new->icon_sprite=sprite;
0202   new->left=x;
0203   new->title=StrNew(title);
0204   new->cnt=to;
0205   QueIns(new,Fs->next_ctrl);
0206   return new;
0207 }
0208 
0209 //
0210 // "New Ant" button
0211 // 
0212 class CAntBttnCtrl:CCounterCtrl {
0213 CAntColony *colony;
0214 };
0215 
0216 U0 NewAntDraw(CDC *dc,CAntBttnCtrl *btn) {
0217   U8 *title=MStrPrint("%s:%d",btn->title,QueCnt(&btn->colony->ants));
0218   U8 *spr;
0219   CDC *dummy;
0220   I64 minx,miny,maxx,maxy,w,h;
0221   dc->color=DKGRAY;
0222   GrRect(dc,btn->left,btn->top,COUNTER_W,COUNTER_H);
0223   dc->color=YELLOW;
0224   dc->thick=2;
0225   GrBorder(dc,btn->left+4,btn->top+4,btn->left+COUNTER_W-4,btn->top+COUNTER_H-4);
0226   dc->color=WHITE;
0227   GrPutS(dc,btn->left+COUNTER_W/2-StrLen(title)*FONT_WIDTH/2.,btn->top+FONT_HEIGHT+2,title);
0228   if(spr=btn->icon_sprite) {
0229     SpriteExtents(spr,&minx,&maxx,&miny,&maxy);
0230     w=maxx-minx;
0231     h=maxy-miny;
0232 //AVOID FLOOD FILLS MAKING STUFF STANGE
0233     dummy=DCNew(w,h);
0234     DCFill(dummy,TRANSPARENT);
0235     Sprite3(dummy,-minx,-miny,0,spr);
0236     GrBlot(dc,btn->left+COUNTER_W/2-w/2,btn->top+COUNTER_H/2-h/2,dummy);
0237     DCDel(dummy);
0238   }
0239   Free(title);
0240 }
0241 
0242 
0243 CAntBttnCtrl *NewAntButtton(U8 *title,U8 *sprite,I64 x,CAntColony *colony) {
0244   CAntBttnCtrl *new=CAlloc(sizeof CCounterCtrl);
0245   new->flags=CTRLF_SHOW;
0246   new->win_task=Fs;
0247   new->update_derived_vals=&CounterUpdateVals;
0248   new->draw_it=&NewAntDraw;
0249   new->left=x;
0250   new->title=StrNew(title);
0251   new->icon_sprite=sprite;
0252   new->colony=colony;
0253   QueIns(new,Fs->last_ctrl);
0254   return new;
0255 }
0256 
0257 
0258 
0259 
0260 <1>
0261 0262 0263 0264 0265 <2>
0266 0267 0268 0269 0270 0271 // 0272 // World Code(Draw) 0273 // 0274 0275 <3>
//Dirt 0276 //// 0277 //// 0278 //// 0279 ////? 0280 0281 <4>
//Water 0282 //// 0283 //// 0284 //// 0285 ///// 0286 0287 <5>
//Water top(1) Animated 0288 //// 0289 //// 0290 //// 0291 ///// 0292 0293 <6>
//Water top(2) Animated 0294 //// 0295 //// 0296 //// 0297 ///// 0298 <7>
//Black background 0299 //// 0300 //// 0301 //// 0302 ///// 0303 0304 0305 <8>
//Grass Top 0306 //// 0307 //// 0308 //// 0309 ///// 0310 <9>
//Grass Right 0311 //// 0312 //// 0313 //// 0314 ///// 0315 0316 <10>
//Grass Right 0317 //// 0318 //// 0319 //// 0320 ///// 0321 <11>
//Sky 0322 //// 0323 //// 0324 //// 0325 ///// 0326 <12>
//Rock 0327 //// 0328 //// 0329 //// 0330 ///// 0331 0332 Bool IsEmpty(I64 color) { 0333 return color==TRANSPARENT||color==WORLD_BLACK||color==-1; 0334 } 0335 Bool IsDirt(I64 color) { 0336 return color==WORLD_DIRT1||color==WORLD_DIRT2; 0337 } 0338 Bool IsGrass(I64 color) { 0339 //WORLD_BLACK is like dirt sort of 0340 return color==WORLD_GRASS1||color==WORLD_GRASS2||IsDirt(color)||color==WORLD_BLACK; 0341 } 0342 Bool IsWater(I64 color) { 0343 switch(color) { 0344 case WORLD_WATER1: 0345 case WORLD_WATER2: 0346 case WORLD_WATER3: 0347 case WORLD_WATER4: 0348 return TRUE; 0349 } 0350 return FALSE; 0351 } 0352 U8 *WorldPixelToSprite(I64 x,I64 y) { 0353 I64 color=GrPeek(world.bitmap,x,y); 0354 Bool left,right; 0355 static U8 *anim=NULL; 0356 again: 0357 switch(color) { 0358 case WORLD_DIRT1: 0359 case WORLD_DIRT2: 0360 return <3>; 0361 case WORLD_GRASS1: 0362 case WORLD_GRASS2: 0363 if(IsGrass(GrPeek(world.bitmap,x,y-1))||IsDirt(GrPeek(world.bitmap,x,y-1))) { 0364 //Choose dirt if grass is on top 0365 world.bitmap->color=WORLD_DIRT1; 0366 GrPlot(world.bitmap,x,y); 0367 color=WORLD_DIRT1; 0368 goto again; 0369 } 0370 left=IsGrass(GrPeek(world.bitmap,x-1,y)); 0371 right=IsGrass(GrPeek(world.bitmap,x+1,y)); 0372 if(left^^right) { 0373 if(left) return <9>; 0374 return <10>; 0375 } 0376 return <8>; 0377 case WORLD_WATER1: 0378 case WORLD_WATER2: 0379 case WORLD_WATER3: 0380 case WORLD_WATER4: 0381 if(!IsWater(GrPeek(world.bitmap,x,y-1))) { 0382 if(Blink) 0383 return <5>; 0384 return <6>; 0385 } 0386 return <4>; 0387 case WORLD_ROCK1: 0388 case WORLD_ROCK2: 0389 return <12>; 0390 case WORLD_BLACK: 0391 return <7>; 0392 } 0393 //Sky 0394 return NULL; 0395 // return <11>; 0396 }; 0397 0398 0399 //This load world data from a bitmap 0400 U0 WorldBlotFromDC(I64 wx,I64 wy,CDC *dc,Bool underground_only=FALSE) { 0401 I64 x,y,c; 0402 for(x=0;x!=dc->width;x++) 0403 for(y=0;y!=dc->height;y++) { 0404 if(underground_only&&!IsDirt(GrPeek(world.bitmap,wx+x,wy+y))) 0405 goto skip; 0406 c=GrPeek(dc,x,y); 0407 switch(c) { 0408 start: 0409 if(!IsEmpty(c)) { 0410 world.bitmap->color=WORLD_BLACK; 0411 GrPlot(world.bitmap,wx+x,wy+y); 0412 } 0413 case WORLD_FOOD1: 0414 NewPieItem(wx+x,wy+y); 0415 break; 0416 case WORLD_FOOD2: 0417 NewMelonItem(wx+x,wy+y); 0418 break; 0419 end: 0420 break; 0421 case WORLD_DIRT1: 0422 case WORLD_DIRT2: 0423 case WORLD_GRASS1: 0424 case WORLD_GRASS2: 0425 case WORLD_WATER1: 0426 case WORLD_WATER2: 0427 case WORLD_WATER3: 0428 case WORLD_WATER4: 0429 case WORLD_ROCK1: 0430 case WORLD_ROCK2: 0431 case WORLD_BLACK: 0432 world.bitmap->color=c; 0433 GrPlot(world.bitmap,wx+x,wy+y); 0434 break; 0435 } 0436 skip:; 0437 } 0438 } 0439 U0 WorldBlotFromSprite(I64 wx,I64 wy,CDC *spr,Bool underground_only=FALSE) { 0440 I64 mnx,mny,mxx,mxy; 0441 CDC *dc; 0442 SpriteExtents(spr,&mnx,&mxx,&mny,&mxy); 0443 dc=DCNew(mxx-mnx+1,mxy-mny+1); 0444 DCFill(dc,TRANSPARENT); 0445 Sprite3(dc,-mnx,-mny,0,spr); 0446 WorldBlotFromDC(wx-mnx,wy-mny,dc,underground_only); 0447 DCDel(dc); 0448 } 0449 0450 // Structures 0451 <13>
0452 0453 0454 0455 0456 <14>
0457 0458 0459 0460 <15>
0461 0462 0463 0464 0465 <16>
0466 0467 0468 // 0469 0470 U0 WorldGen(I64 w,I64 h=127) { 0471 I64 *ground_elevations=CAlloc(sizeof(I64)*w); 0472 I64 x,y,old_x,old_y; 0473 I64 base_evel=20; 0474 I64 min_elev=base_evel-10; 0475 I64 max_elev=base_evel+10; 0476 I64 idx; 0477 F64 delta,density; 0478 U8 *spr; 0479 //Phase 1 make land 0480 world.bitmap=DCNew(w,h); 0481 DCFill(world.bitmap,TRANSPARENT); 0482 world.bitmap->color=WORLD_GRASS1; 0483 world.bitmap->thick=2; 0484 y=base_evel; 0485 for(x=0;x<w;) { 0486 old_x=x; 0487 old_y=y; 0488 x+=RandU64&15+1; 0489 delta=(Rand-.5)*10; 0490 if(y+delta>=max_elev) { 0491 y=max_elev-delta; //Change direction 0492 } else if(y+delta<=min_elev) { 0493 y=min_elev+delta; //Change direction 0494 } else 0495 y=ClampI64(y+delta,min_elev,max_elev); 0496 GrLine3(world.bitmap,old_x,old_y,0,x,y,0); 0497 for(;old_x!=x;old_x++) { 0498 ground_elevations[old_x]=old_y; 0499 } 0500 } 0501 //Phase 2 fill in bottom of world with dirt 0502 world.bitmap->color=WORLD_DIRT1; 0503 GrFloodFill(world.bitmap,1,h-1); 0504 //Phase 3. underground Populate structuree from sprites 0505 density=3.5*128/w+3; 0506 for(x=0;x<w;x+=128) { 0507 for(idx=0;idx<density;idx++) { 0508 old_x=x+Rand*128; 0509 old_y=(h-ground_elevations[old_x])*Rand; 0510 old_y+=ground_elevations[old_x]; 0511 switch(RandU64%4) { 0512 case 0: 0513 spr=<13>; 0514 break; 0515 case 1: 0516 spr=<14>; 0517 break; 0518 case 2: 0519 spr=<15>; 0520 break; 0521 case 3: 0522 spr=<16>; 0523 break; 0524 } 0525 WorldBlotFromSprite(old_x,old_y,spr,TRUE); 0526 } 0527 } 0528 Free(ground_elevations); 0529 } 0530 #define TILE_SZ 30 0531 U0 DrawWorld(CDC *dc,CTask *t) { 0532 I64 pan_x=world.cam_x,pan_y=world.cam_y; 0533 F64 zoom=world.cam_zoom; 0534 I64 matrix[16]; 0535 CItem *item; 0536 CAntColony *c; 0537 CAntCommand *com; 0538 CDC *dummy; 0539 CAnt *ant; 0540 I64 tx=pan_x/(TILE_SZ*zoom),ty=pan_y/(TILE_SZ*zoom); 0541 I64 minx,maxx,miny,maxy; 0542 CD2I64 center; 0543 Mat4x4IdentEqu(matrix); 0544 Mat4x4Scale(matrix,zoom); 0545 //Background sky 0546 TextRect(t->win_left,t->win_right,t->win_top,t->win_bottom,CYAN<<8|CYAN<<12); 0547 F64 x,y; 0548 U8 *spr; 0549 for(y=0;y<TILE_SZ+Ceil(t->pix_height/zoom);y+=TILE_SZ) 0550 for(x=0;x<TILE_SZ+Ceil(t->pix_width/zoom);x+=TILE_SZ) { 0551 spr=WorldPixelToSprite(tx+x/TILE_SZ,ty+y/TILE_SZ); 0552 if(spr) 0553 Sprite3Mat4x4B(dc,-pan_x%(TILE_SZ*zoom)+x*zoom,-pan_y%(TILE_SZ*zoom)+y*zoom,0,spr,matrix); 0554 } 0555 for(item=world.items.next;item!=&world.items;item=item->next) { 0556 x=(item->position.x*TILE_SZ)*zoom-pan_x+TILE_SZ/2*zoom; 0557 y=(item->position.y*TILE_SZ)*zoom-pan_y+TILE_SZ/2*zoom; 0558 if(spr=item->spr) { 0559 dummy=Sprite2DCMat4x4B(spr,matrix,&center); 0560 GrBlot(dc,x-center.x,y-center.y,dummy); 0561 DCDel(dummy); 0562 } 0563 } 0564 for(c=world.colonies.next;c!=&world.colonies;c=c->next) { 0565 for(ant=c->ants.next;ant!=&c->ants;ant=ant->next) { 0566 if(Blink&&ant->sprite2) 0567 spr=ant->sprite2; 0568 else 0569 spr=ant->sprite; 0570 if(spr) { 0571 x=(ant->position.x)*zoom-pan_x; 0572 y=(ant->position.y)*zoom-pan_y; 0573 Mat4x4IdentEqu(matrix); 0574 Mat4x4Scale(matrix,zoom); 0575 Mat4x4RotZ(matrix,ant->rot); 0576 if(ant->reflecty) Mat4x4RotX(matrix,pi); 0577 if(ant->reflectx) Mat4x4RotY(matrix,pi); 0578 dummy=Sprite2DCMat4x4B(spr,matrix,&center,ant->color); 0579 GrBlot(dc,x-center.x,y-center.y,dummy); 0580 DCDel(dummy); 0581 } 0582 } 0583 Mat4x4IdentEqu(matrix); 0584 Mat4x4Scale(matrix,zoom); 0585 for(com=c->commands.next;com!=&c->commands;com=com->next) { 0586 spr=com->spr; 0587 if(!com->follow_item) { 0588 x=(com->x*TILE_SZ)*zoom-pan_x; 0589 y=(com->y*TILE_SZ)*zoom-pan_y; 0590 } else { 0591 item=com->follow_item; 0592 x=(item->position.x*TILE_SZ)*zoom-pan_x; 0593 y=(item->position.y*TILE_SZ)*zoom-pan_y; 0594 } 0595 if(spr) { 0596 dummy=Sprite2DCMat4x4B(spr,matrix,&center); 0597 GrBlot(dc,x-center.x+TILE_SZ/2*zoom,y-center.y+TILE_SZ/2*zoom,dummy); 0598 DCDel(dummy); 0599 } 0600 } 0601 } 0602 } 0603 // 0604 // World(Camera Control) 0605 // 0606 #define CAM_MOVE_MARGIN 50 0607 0608 U0 ScrnCordsToWorldCoords(CD2 *w,I64 msx,I64 msy) { 0609 F64 zoom=world.cam_zoom; 0610 w->x=Floor(msx/zoom)+Floor(world.cam_x/zoom); 0611 w->y=Floor(msy/zoom)+Floor(world.cam_y/zoom); 0612 } 0613 0614 0615 U0 WorldCameraControl(I64 type,I64 m1,I64 m2) { 0616 static I64 lastz=ms.pos.z; 0617 F64 wx,wy,zoom,ozoom; 0618 static I64 old_x,old_y; 0619 CD2 dummy; 0620 if(type==MSG_MS_MOVE) { 0621 old_x=m1,old_y=m2; 0622 } 0623 if(lastz!=ms.pos.z) { 0624 //Move around cursor 0625 zoom=world.cam_zoom; 0626 wx=old_x/zoom+world.cam_x/zoom; 0627 wy=old_y/zoom+world.cam_y/zoom; 0628 wx/=TILE_SZ; 0629 wy/=TILE_SZ; 0630 world.cam_zoom=Clamp(zoom-(ms.pos.z-lastz)*1/8.,1/4.,2.); 0631 zoom=world.cam_zoom; 0632 world.cam_x=(wx*TILE_SZ-old_x/zoom)*zoom; 0633 world.cam_y=(wy*TILE_SZ-old_y/zoom)*zoom; 0634 lastz=ms.pos.z; 0635 world.cam_x=ClampI64(world.cam_x,0,world.bitmap->width*TILE_SZ); 0636 world.cam_y=ClampI64(world.cam_y,-64,128*TILE_SZ); 0637 } 0638 if(Bt(kbd.down_bitmap,SC_CURSOR_UP)) { 0639 world.cam_y=ClampI64(world.cam_y-15,-64,128*TILE_SZ); 0640 } 0641 if(Bt(kbd.down_bitmap,SC_CURSOR_DOWN)) { 0642 world.cam_y=ClampI64(world.cam_y+15,-64,128*TILE_SZ); 0643 } 0644 if(Bt(kbd.down_bitmap,SC_CURSOR_RIGHT)) { 0645 world.cam_x=ClampI64(world.cam_x+15,0,world.bitmap->width*TILE_SZ); 0646 } 0647 if(Bt(kbd.down_bitmap,SC_CURSOR_LEFT)) { 0648 world.cam_x=ClampI64(world.cam_x-15,0,world.bitmap->width*TILE_SZ); 0649 } 0650 } 0651 // 0652 // Ants 0653 // 0654 0655 0656 //Frame 1 0657 0658 0659 0660 <17>
0661 0662 0663 //Frame 2 0664 0665 0666 0667 0668 0669 0670 <18>
0671 0672 0673 0674 0675 //Queen 0676 0677 0678 0679 0680 0681 0682 0683 0684 <19>
0685 0686 0687 0688 0689 CAnt *NewQueenAnt(CAntColony *colony,I64 x=0,I64 y=0) { 0690 CAnt *ant=CAlloc(sizeof CAnt,ant_task); 0691 ant->colony=colony; 0692 if(!x||!y) { 0693 ant->position.x=colony->colony_center.x*TILE_SZ+TILE_SZ/2; 0694 ant->position.y=colony->colony_center.y*TILE_SZ+TILE_SZ/2; 0695 } else { 0696 ant->position.x=x*TILE_SZ+TILE_SZ/2; 0697 ant->position.y=y*TILE_SZ+TILE_SZ/2; 0698 } 0699 ant->rot=0; 0700 ant->color=colony->color; 0701 ant->sprite=<19>; 0702 ant->is_queen=TRUE; 0703 QueInit(&ant->ai_commands); 0704 QueIns(ant,&colony->ants); 0705 return ant; 0706 } 0707 #define WORKER_SPEED 2.5 0708 0709 Bool AntIsOnWall(I64 tx,I64 ty,I64 dir=I64_MIN) { 0710 F64 angle; 0711 I64 cnt; 0712 Bool directions[8]; 0713 0714 0715 0716 0717 0718 0719 <20>
; 0720 0721 0722 0723 0724 0725 0726 0727 0728 angle=0; 0729 for(cnt=0;cnt!=8;cnt++) { 0730 directions[cnt]=!IsEmpty( 0731 GrPeek(world.bitmap, 0732 tx+ToI64(1.8*Cos(angle)), 0733 ty+ToI64(1.8*Sin(angle)) 0734 ) 0735 ); 0736 angle+=2*pi/8; 0737 } 0738 if(dir==I64_MIN) { 0739 cnt=8; 0740 while(--cnt>=0) 0741 if(directions[cnt]) 0742 return TRUE; 0743 return FALSE; 0744 } 0745 dir&=7; 0746 if(directions[dir]) 0747 return TRUE; 0748 return FALSE; 0749 } 0750 0751 Bool AntCornerIsAvail(I64 tx,I64 ty,I64 dir,I64 left) { 0752 F64 angle; 0753 I64 cnt; 0754 Bool directions[8]; 0755 0756 0757 0758 0759 0760 0761 <20>
; 0762 0763 0764 0765 0766 0767 0768 0769 0770 angle=0; 0771 for(cnt=0;cnt!=8;cnt++) { 0772 directions[cnt]=!IsEmpty( 0773 GrPeek(world.bitmap, 0774 tx+ToI64(1.8*Cos(angle)), 0775 ty+ToI64(1.8*Sin(angle)) 0776 ) 0777 ); 0778 angle+=2*pi/8; 0779 } 0780 0781 dir&=7; 0782 if(!left) { 0783 return !directions[dir]&&!directions[(dir+1)&7]; 0784 } 0785 return !directions[dir]&&!directions[(dir-1)&7]; 0786 } 0787 Bool AntDirectionAvail(I64 tx,I64 ty,I64 dir,Bool going_left=FALSE) { 0788 F64 angle; 0789 I64 cnt; 0790 Bool directions[8]; 0791 0792 0793 0794 0795 0796 0797 <20>
; 0798 0799 0800 0801 0802 0803 0804 0805 0806 angle=0; 0807 for(cnt=0;cnt!=8;cnt++) { 0808 directions[cnt]=!IsEmpty( 0809 GrPeek(world.bitmap, 0810 tx+ToI64(1.8*Cos(angle)), 0811 ty+ToI64(1.8*Sin(angle)) 0812 ) 0813 ); 0814 angle+=2*pi/8; 0815 } 0816 0817 dir&=7; 0818 if(!going_left) { 0819 if(!directions[dir]&&directions[(dir+1)&7]) 0820 return TRUE; 0821 } else { 0822 if(!directions[dir]&&directions[(dir-1)&7]) 0823 return TRUE; 0824 } 0825 return FALSE; 0826 } 0827 Bool AntLatchToWall(CWorker *ant) { 0828 Bool success=FALSE; 0829 I64 dir=ant->direction,cnt; 0830 if(!ant->going_left) { 0831 if(!AntIsOnWall(ant->tile_x,ant->tile_y,dir*2+2)) 0832 for(cnt=0;cnt!=4;cnt++) { 0833 if(AntIsOnWall(ant->tile_x,ant->tile_y,dir*2+cnt*2+2)) { 0834 dir+=cnt; 0835 success=TRUE; 0836 break; 0837 } 0838 } else 0839 success=TRUE; 0840 } else { 0841 if(!AntIsOnWall(ant->tile_x,ant->tile_y,dir*2-2)) { 0842 for(cnt=0;cnt!=4;cnt++) { 0843 if(AntIsOnWall(ant->tile_x,ant->tile_y,dir*2-cnt*2-2)) { 0844 dir-=cnt; 0845 success=TRUE; 0846 break; 0847 } 0848 } 0849 } else 0850 success=TRUE; 0851 } 0852 ant->direction=dir&3; 0853 return success; 0854 } 0855 0856 Bool AntCanSwitchSides(CWorker *ant) { 0857 if(AntIsOnWall(ant->tile_x,ant->tile_y,2*ant->direction+2)) { 0858 if(AntIsOnWall(ant->tile_x,ant->tile_y,2*ant->direction+4+2)) { 0859 return TRUE; 0860 } 0861 } 0862 return FALSE; 0863 } 0864 0865 Bool AntAtJunction(CWorker *ant) { 0866 I64 dir=2*ant->direction; 0867 I64 tx=ant->tile_x; 0868 I64 ty=ant->tile_y; 0869 if(AntCanSwitchSides(ant)) 0870 if(AntDirectionAvail(tx,ty,dir+1)||AntDirectionAvail(tx,ty,dir-1)) 0871 return TRUE; 0872 return FALSE; 0873 } 0874 0875 //https://stackoverflow.com/questions/1878907/how-can-i-find-the-smallest-difference-between-two-angles-around-a-point 0876 F64 AngleBetween(F64 a,F64 b) { 0877 return pi-Abs(Abs(a-b)%(2*pi)-pi); 0878 } 0879 //force_direction is 0,1 or -1 0880 U0 AntWanderNext(CWorker *ant,I64 force_direction=0) { 0881 F64 angle,base; 0882 I64 dir,odir=ant->direction; 0883 AntLatchToWall(ant); 0884 dir=ant->direction; 0885 //If we are at a junction,choose path closer towards our destination 0886 if(AntCanSwitchSides(ant)) { 0887 base=(2*dir)*2*pi/8; 0888 if(ant->going_left) 0889 base+=pi; 0890 angle=Arg(ant->wander_towards.x-ant->tile_x,ant->wander_towards.y-ant->tile_y); 0891 if(!force_direction&&AngleBetween(angle,base+pi/4)>AngleBetween(angle,base-pi/4)) { 0892 dir+=2; 0893 } else if(force_direction==1) { 0894 dir+=2; 0895 } else 0896 dir+=0; 0897 } 0898 dir=ant->direction; 0899 if(!ant->going_left) { 0900 if(AntDirectionAvail(ant->tile_x,ant->tile_y,dir*2)) { 0901 angle=(dir)*2*pi/4; 0902 ant->tile_x+=ToI64(1.8*Cos(angle)); 0903 ant->tile_y+=ToI64(1.8*Sin(angle)); 0904 } else if(AntCornerIsAvail(ant->tile_x,ant->tile_y,dir*2,FALSE)) { 0905 angle=(2*dir)*2*pi/8+pi/4; 0906 AntLatchToWall(ant); 0907 dir=ant->direction; 0908 ant->tile_x+=ToI64(1.8*Cos(angle)); 0909 ant->tile_y+=ToI64(1.8*Sin(angle)); 0910 } else { 0911 dir+=3; 0912 } 0913 } else { 0914 if(AntDirectionAvail(ant->tile_x,ant->tile_y,(dir)*2,TRUE)) { 0915 angle=dir*2*pi/4; 0916 ant->tile_x+=ToI64(1.8*Cos(angle)); 0917 ant->tile_y+=ToI64(1.8*Sin(angle)); 0918 } else if(AntCornerIsAvail(ant->tile_x,ant->tile_y,dir*2,TRUE)) { 0919 angle=dir*2*pi/4-pi/4; 0920 AntLatchToWall(ant); 0921 dir=ant->direction; 0922 ant->tile_x+=ToI64(1.8*Cos(angle)); 0923 ant->tile_y+=ToI64(1.8*Sin(angle)); 0924 } else { 0925 dir++; 0926 } 0927 } 0928 ant->direction=dir; 0929 ant->direction&=3; 0930 AntLatchToWall(ant); 0931 } 0932 Bool _WorkerWanderAI(CWorker *ant,I64 force_dir=0) { 0933 if(ant->steps_to_walk<=0) { 0934 return FALSE; 0935 } 0936 F64 angle; 0937 Bool directions[8]; 0938 I64 cnt,dir,odir; 0939 I64 on_top; 0940 I64 on_left; 0941 I64 on_right; 0942 I64 on_bottom; 0943 if(ant->going_left) { 0944 on_top=ant->direction==0; 0945 on_left=ant->direction==3; 0946 on_right=ant->direction==1; 0947 on_bottom=ant->direction==2; 0948 } else { 0949 on_left=ant->direction==1; 0950 on_right=ant->direction==3;; 0951 on_top=ant->direction==2; 0952 on_bottom=ant->direction==0; 0953 } 0954 if(!ant->going_left) 0955 ant->distance+=WORKER_SPEED; 0956 else 0957 ant->distance-=WORKER_SPEED; 0958 if(0.<=ant->distance<=TILE_SZ) { 0959 draw: 0960 ant->position.x=TILE_SZ*ant->tile_x; 0961 ant->position.y=TILE_SZ*ant->tile_y; 0962 if(on_top) { 0963 ant->rot=pi; 0964 ant->reflecty=FALSE; 0965 ant->reflectx=ant->going_left; 0966 ant->position.x+=TILE_SZ-ant->distance; 0967 } else if(on_right) { 0968 ant->rot=-pi/2; 0969 ant->position.y+=TILE_SZ-ant->distance; 0970 ant->position.x+=TILE_SZ; 0971 ant->reflectx=FALSE; 0972 ant->reflecty=ant->going_left; 0973 } else if(on_left) { 0974 ant->rot=pi/2; 0975 ant->reflectx=FALSE; 0976 ant->reflecty=ant->going_left; 0977 ant->position.y+=ant->distance; 0978 } else { //bottom 0979 ant->reflecty=FALSE; 0980 ant->reflectx=ant->going_left; 0981 ant->position.x+=ant->distance; 0982 ant->position.y+=TILE_SZ; 0983 ant->rot=0.; 0984 } 0985 } else { 0986 AntWanderNext(ant,force_dir); 0987 ant->steps_to_walk--; 0988 if(!ant->going_left) 0989 ant->distance=0; 0990 else 0991 ant->distance=TILE_SZ-1.; 0992 } 0993 return TRUE; 0994 } 0995 #define GRAVITY 1. 0996 U0 AntFall(CWorker *ant) { 0997 ant->fall_speed=0; 0998 I64 o_y,to_y; 0999 while(!AntIsOnWall(ant->tile_x,ant->tile_y,2)) { 1000 ant->tile_x=ant->position.x/TILE_SZ; 1001 ant->tile_y=ant->position.y/TILE_SZ; 1002 ant->fall_speed+=GRAVITY; 1003 ant->position.y+=ant->fall_speed; 1004 ant->reflectx=FALSE; 1005 ant->reflecty=FALSE; 1006 ant->rot+=tS*pi; 1007 to_y=ant->position.y/TILE_SZ; 1008 while(ant->tile_y<to_y) { 1009 ant->tile_y++; 1010 if(AntIsOnWall(ant->tile_x,ant->tile_y,2)) 1011 return; 1012 } 1013 Refresh; 1014 } 1015 } 1016 U0 WorkerWanderAI(CWorker *ant,I64 force_dir=0) { 1017 I64 first=0; 1018 while(_WorkerWanderAI(ant,force_dir)) { 1019 while(!AntIsOnWall(ant->tile_x,ant->tile_y)) { 1020 AntFall(ant); 1021 } 1022 if(AntAtJunction(ant)&&force_dir&&!first) 1023 break; 1024 first=1; 1025 Refresh; 1026 } 1027 } 1028 CAnt *NewWorkerAnt(CAntColony *colony,I64 x=0,I64 y=0) { 1029 CWorker *ant=CAlloc(sizeof(CWorker),ant_task); 1030 ant->colony=colony; 1031 if(!x||!y) { 1032 ant->position.x=colony->colony_center.x*TILE_SZ+TILE_SZ/2; 1033 ant->position.y=colony->colony_center.y*TILE_SZ+TILE_SZ/2; 1034 } else { 1035 ant->position.x=x*TILE_SZ+TILE_SZ/2; 1036 ant->position.y=y*TILE_SZ+TILE_SZ/2; 1037 } 1038 ant->rot=0; 1039 ant->color=colony->color; 1040 ant->sprite=<17>; 1041 ant->sprite2=<18>; 1042 ant->tile_x=ant->position.x/TILE_SZ; 1043 ant->tile_y=ant->position.y/TILE_SZ; 1044 ant->distance=TILE_SZ/2; 1045 ant->steps_to_walk=1; 1046 ant->ai_task=Spawn(&WorkerAntAITask,ant,"AntWorker",,Fs); 1047 QueInit(&ant->ai_commands); 1048 QueIns(ant,&colony->ants); 1049 return ant; 1050 } 1051 1052 CAntColony *NewColony(I64 x,I64 y,Bool player=TRUE) { 1053 CAntColony *ret=CAlloc(sizeof CAntColony); 1054 I64 have; 1055 ret->food=100; 1056 ret->dirt=10; 1057 ret->color=BLUE; 1058 QueInit(&ret->ants); 1059 QueInit(&ret->ai_wants); 1060 QueInit(&ret->commands); 1061 ret->player=player; 1062 ret->colony_center.x=x; 1063 ret->colony_center.y=y; 1064 if(player) { 1065 CounterNew("Food",<1>,0,&ret->food); 1066 CounterNew("Dirt",<2>,COUNTER_W,&ret->dirt); 1067 } 1068 1069 world.bitmap->color=WORLD_BLACK; 1070 //Make a center for the ant colony 1071 GrRect(world.bitmap,x-2,y-4,5,5); 1072 while(TRUE) { 1073 have=GrPeek(world.bitmap,x,y); 1074 if(have!=TRANSPARENT&&have!=-1) { 1075 GrPlot(world.bitmap,x,y); 1076 y--; 1077 } else 1078 break; 1079 } 1080 1081 NewQueenAnt(ret); 1082 NewWorkerAnt(ret); 1083 return ret; 1084 } 1085 1086 // 1087 // Pathfinding 1088 // 1089 1090 F64 _WanderTowardsPoint(CWorker *ant,I64 to_x,I64 to_y,I64 steps,Bool allow_junction=TRUE,I64 *_force=NULL,Bool forbid_backwards=FALSE,CD3I64 *closest) { 1091 if(steps<=0) return I32_MAX; 1092 I64 cnt; 1093 I64 old_gl=ant->going_left; 1094 I64 old_dir=ant->direction; 1095 I64 old_tx=ant->tile_x; 1096 I64 old_ty=ant->tile_y; 1097 F64 best=I32_MAX,cur,best2=I32_MAX,cur2; 1098 CD3I64 best_right,best_left; 1099 CDC *nav_dc=ant->nav_visited_dc; 1100 I64 force=0,force_r=0,force_l=0,dx,dy,visited; 1101 ant->going_left=FALSE; 1102 ant->wander_towards.x=to_x; 1103 ant->wander_towards.y=to_y; 1104 cnt=0; 1105 if(forbid_backwards&&old_gl!=FALSE) 1106 goto skip1; 1107 if(allow_junction&&AntAtJunction(ant)) { 1108 cur=_WanderTowardsPoint(ant,to_x,to_y,steps-1,FALSE,,TRUE,closest); 1109 ant->going_left=FALSE; //Reset the going_left 1110 cur2=_WanderTowardsPoint(ant,to_x,to_y,steps-1,FALSE,,TRUE,closest); 1111 ant->going_left=FALSE; //Reset the going_left 1112 if(cur<cur2) { 1113 force_r=1; 1114 } else 1115 force_r=-1; 1116 } 1117 for(cnt=0;cnt!=steps;cnt++) { 1118 cur=Sqrt(Sqr(to_x-ant->tile_x)+Sqr(to_y-ant->tile_y)); 1119 if(cnt&&AntAtJunction(ant)) { 1120 cur=_WanderTowardsPoint(ant,to_x,to_y,steps-cnt,,&force_r,,closest); 1121 if(best>cur) { 1122 best_right.x=ant->tile_x; 1123 best_right.y=ant->tile_y; 1124 best_right.z=cnt+1; 1125 best=cur; 1126 } 1127 break; 1128 } 1129 if(cur<best) { 1130 best=cur; 1131 best_right.x=ant->tile_x; 1132 best_right.y=ant->tile_y; 1133 best_right.z=cnt+1; 1134 } 1135 dx=ant->tile_x; 1136 dy=ant->tile_y; 1137 if(cnt) 1138 AntWanderNext(ant); 1139 else 1140 AntWanderNext(ant,force_r); 1141 dx-=ant->tile_x; 1142 dy-=ant->tile_y; 1143 if(dx||dy) { 1144 visited=GrPeek(nav_dc,ant->tile_x-nav_dc->x,ant->tile_y-nav_dc->y); 1145 if(visited>2) 1146 break; 1147 nav_dc->color=visited+1; 1148 GrPlot(nav_dc,ant->tile_x-nav_dc->x,ant->tile_y-nav_dc->y); 1149 } 1150 } 1151 1152 skip1: 1153 if(forbid_backwards&&old_gl!=TRUE) 1154 goto skip2; 1155 //Restore orig 1156 ant->going_left=TRUE; 1157 ant->direction=old_dir; 1158 ant->tile_x=old_tx; 1159 ant->tile_y=old_ty; 1160 if(allow_junction&&AntAtJunction(ant)) { 1161 cur=_WanderTowardsPoint(ant,to_x,to_y,steps,FALSE,,TRUE,closest); 1162 ant->going_left=TRUE; //Reset the going_left 1163 cur2=_WanderTowardsPoint(ant,to_x,to_y,steps,FALSE,,TRUE,closest); 1164 ant->going_left=TRUE; //Reset the going_left 1165 if(cur<cur2) { 1166 force_l=1; 1167 } else 1168 force_l=-1; 1169 } 1170 for(cnt=0;cnt!=steps;cnt++) { 1171 cur=Sqrt(Sqr(to_x-ant->tile_x)+Sqr(to_y-ant->tile_y)); 1172 if(cnt&&AntAtJunction(ant)) { 1173 cur=_WanderTowardsPoint(ant,to_x,to_y,steps-cnt,,&force_l,,closest); 1174 if(best2>cur) { 1175 best_left.x=ant->tile_x; 1176 best_left.y=ant->tile_y; 1177 best_left.z=cnt+1; 1178 best2=cur; 1179 } 1180 break; 1181 } 1182 if(cur<best2) { 1183 best2=cur; 1184 best_left.x=ant->tile_x; 1185 best_left.y=ant->tile_y; 1186 best_left.z=cnt+1; 1187 } 1188 dx=ant->tile_x; 1189 dy=ant->tile_y; 1190 if(cnt) 1191 AntWanderNext(ant); 1192 else 1193 AntWanderNext(ant,force_l); 1194 dx-=ant->tile_x; 1195 dy-=ant->tile_y; 1196 if(dx||dy) { 1197 visited=GrPeek(nav_dc,ant->tile_x-nav_dc->x,ant->tile_y-nav_dc->y); 1198 if(visited>2) 1199 break; 1200 nav_dc->color=visited+1; 1201 GrPlot(nav_dc,ant->tile_x-nav_dc->x,ant->tile_y-nav_dc->y); 1202 } 1203 } 1204 1205 skip2: 1206 if(best2<best) { 1207 ant->going_left=TRUE; 1208 ant->steps_to_walk=best_left.z; 1209 if(closest) 1210 if(closest->z<best2) { 1211 closest->x=best_left.x; 1212 closest->y=best_left.y; 1213 closest->z=best2; 1214 } 1215 if(_force) *_force=force_l; 1216 } else { 1217 ant->going_left=FALSE; 1218 ant->steps_to_walk=best_right.z; 1219 if(closest) 1220 if(closest->z<best) { 1221 closest->x=best_right.x; 1222 closest->y=best_right.y; 1223 closest->z=best; 1224 } 1225 if(_force) *_force=force_r; 1226 } 1227 ant->direction=old_dir; 1228 ant->tile_x=old_tx; 1229 ant->tile_y=old_ty; 1230 return Min(best,best2); 1231 } 1232 F64 WanderTowardsPoint(CWorker *ant,I64 to_x,I64 to_y,I64 steps,Bool allow_junction=TRUE,I64 *_force=NULL,Bool forbid_backwards=FALSE,CD3I64 *closest=NULL) { 1233 F64 reverse_score=I32_MAX; 1234 F64 forwards_score=I32_MAX,ret; 1235 if(closest) closest->z=I32_MAX; 1236 ant->nav_visited_dc=DCNew(2*steps+1,2*steps+1); 1237 ant->nav_visited_dc->x=ant->tile_x-steps; 1238 ant->nav_visited_dc->y=ant->tile_y-steps; 1239 1240 DCFill(ant->nav_visited_dc,0); 1241 forwards_score=_WanderTowardsPoint(ant,to_x,to_y,steps,allow_junction,_force,forbid_backwards,closest); 1242 ant->direction+=2; 1243 DCFill(ant->nav_visited_dc,0); 1244 reverse_score=_WanderTowardsPoint(ant,to_x,to_y,steps,allow_junction,_force,forbid_backwards,closest); 1245 ant->direction-=2; 1246 DCFill(ant->nav_visited_dc,0); 1247 if(forwards_score<reverse_score) { 1248 ret=_WanderTowardsPoint(ant,to_x,to_y,steps,allow_junction,_force,forbid_backwards,closest); 1249 } else { 1250 ant->direction+=2; 1251 ret=_WanderTowardsPoint(ant,to_x,to_y,steps,allow_junction,_force,forbid_backwards,closest); 1252 } 1253 DCDel(ant->nav_visited_dc); 1254 return ret; 1255 } 1256 Bool AntDig(CWorker *ant,CAntCommand *command) { 1257 if(!IsEmpty(GrPeek(world.bitmap,command->x,command->y))) { 1258 //TODO animation 1259 Sleep(300); 1260 world.bitmap->color=WORLD_BLACK; 1261 ant->colony->dirt++; 1262 GrPlot(world.bitmap,command->x,command->y); 1263 QueRem(command); 1264 Free(command); 1265 return TRUE; 1266 } 1267 return FALSE; 1268 } 1269 Bool AntBuild(CWorker *ant,CAntCommand *command) { 1270 if(ant->colony->dirt<=0) 1271 return FALSE; //TODO ask for dirt 1272 if(IsEmpty(GrPeek(world.bitmap,command->x,command->y))) { 1273 //TODO animation and adjsut dist count 1274 Sleep(100); 1275 world.bitmap->color=WORLD_DIRT1; 1276 QueRem(command); 1277 Free(command); 1278 GrPlot(world.bitmap,command->x,command->y); 1279 return TRUE; 1280 } 1281 return FALSE; 1282 } 1283 CAntCommand *NearestCommand(CWorker *ant) { 1284 F64 best_dist=I32_MAX,dist,angle; 1285 CAntCommand *com,*best=NULL; 1286 //Check ant-specific commands first 1287 for(com=ant->ai_commands.next;com!=&ant->ai_commands;com=com->next) { 1288 if(com->follow_item&&ValidateItem(com->follow_item)) { 1289 com->x=com->follow_item->position.x; 1290 com->y=com->follow_item->position.y; 1291 } 1292 dist=Sqrt(Sqr(com->x-ant->tile_x)+Sqr(com->y-ant->tile_y)); 1293 if(dist<best_dist) { 1294 best=com; 1295 best_dist=dist; 1296 } 1297 } 1298 for(com=ant->colony->commands.next;com!=&ant->colony->commands;com=com->next) { 1299 if(com->follow_item&&ValidateItem(com->follow_item)) { 1300 com->x=com->follow_item->position.x; 1301 com->y=com->follow_item->position.y; 1302 } 1303 dist=Sqrt(Sqr(com->x-ant->tile_x)+Sqr(com->y-ant->tile_y)); 1304 if(dist<best_dist) { 1305 best=com; 1306 best_dist=dist; 1307 } 1308 } 1309 return best; 1310 } 1311 CItem *ItemAtPos(I64 x,I64 y) { 1312 CItem *item; 1313 for(item=world.items.next;item!=&world.items;item=item->next) { 1314 if(item->position.x==x&&item->position.y==y) { 1315 return item; 1316 } 1317 } 1318 return NULL; 1319 } 1320 U0 WorkerAntAITask(CWorker *ant) { 1321 //Paths is the CD2I32 of where to go 1322 I64 state,force_dir; 1323 I64 look_dist; 1324 CAntCommand *com; 1325 CAntColony *colony=ant->colony; 1326 CItem *item; 1327 try 1328 while(TRUE) { 1329 com=NearestCommand(ant); 1330 look_dist=10; 1331 if(ant->return_to_queen) { 1332 look_dist=50; 1333 //Near queen? 1334 if(AbsI64(colony->colony_center.x-ant->tile_x)<=1&&AbsI64(colony->colony_center.y-ant->tile_y)<=1) { 1335 if(ValidateItem(item=ant->carry)) { 1336 if(item->ident=='Food') { 1337 //Give queen the food 1338 ant->colony->food+=item->user_data; 1339 ant->carry=NULL; 1340 QueRem(item); 1341 Free(item); 1342 ant->return_to_queen=FALSE; 1343 } 1344 } 1345 } 1346 ant->wander_towards.x=ant->colony->colony_center.x; 1347 ant->wander_towards.y=ant->colony->colony_center.y; 1348 } else if(com) { 1349 ant->wander_towards.x=com->x; 1350 ant->wander_towards.y=com->y; 1351 } else { 1352 ant->wander_towards.x=0; 1353 ant->wander_towards.y=0; 1354 } 1355 if(ant->wander_towards.y||ant->wander_towards.x); { 1356 WanderTowardsPoint(ant,ant->wander_towards.x,ant->wander_towards.y,look_dist,NULL); 1357 } 1358 ant->steps_to_walk=MinI64(ant->steps_to_walk,5); 1359 WorkerWanderAI(ant,force_dir); 1360 com=NearestCommand(ant); 1361 if(com) { 1362 //If the food is at current position 1363 if(com->x==ant->tile_x&&com->y==ant->tile_y) { 1364 if(com->type=='Eat') { 1365 eat: 1366 if(!ant->carry) { 1367 ant->return_to_queen=TRUE; 1368 ant->carry=com->follow_item; 1369 QueRem(com); 1370 Free(com); 1371 } 1372 } 1373 } 1374 1375 //Check if our destinarion is 1 block from our command 1376 else if(com->x!=ant->tile_x||com->y!=ant->tile_y) {//Dont build at current location 1377 if(AbsI64(com->x-ant->tile_x)<=1&&AbsI64(com->y-ant->tile_y)<=1) { 1378 if(com->type=='Dig') { 1379 AntDig(ant,com); 1380 } else if(com->type=='Build') { 1381 AntBuild(ant,com); 1382 } else if(com->type=='Eat') 1383 goto eat; 1384 } 1385 } 1386 } 1387 Refresh; 1388 } 1389 catch 1390 DbgPrint("ASS:%c",Fs->except_ch); 1391 } 1392 // 1393 // Items 1394 // 1395 1396 1397 1398 1399 <21>
1400 1401 1402 1403 CItem *NewPieItem(I64 x,I64 y) { 1404 CItem *food=CAlloc(sizeof(CItem),ant_task); 1405 food->spr=<1>; 1406 food->user_data=10; //10 food 1407 food->position.x=x; 1408 food->position.y=y; 1409 food->ident='Food'; 1410 QueIns(food,&world.items); 1411 return food; 1412 } 1413 1414 CItem *NewMelonItem(I64 x,I64 y) { 1415 CItem *food=CAlloc(sizeof(CItem),ant_task); 1416 food->spr=<21>; 1417 food->user_data=50; //50 food 1418 food->position.x=x; 1419 food->position.y=y; 1420 food->ident='Food'; 1421 QueIns(food,&world.items); 1422 return food; 1423 } 1424 1425 // 1426 // Enemy Ants AI 1427 // 1428 1429 //These functions return a score based on circumsatnce 1430 //This will dig a path/make a path 1431 F64 AntsNearPointScore(CAntColony *colony,I64 x,I64 y,F64 decay=.1) { 1432 CWorker *ant; 1433 I64 divide=0; 1434 F64 score=0,bungis=Sqr(world.bitmap->width); 1435 for(ant=colony->ants.next;ant!=colony;ant=ant->next) { 1436 divide++; 1437 score+=Max(bungis-Sqrt(Sqr(ant->tile_x-x)+Sqr(ant->tile_y-y))*decay,0.); 1438 } 1439 if(!divide) 1440 return 0.; 1441 return 1.-score/(bungis*divide); 1442 } 1443 #define DIRT_SCORE .05 1444 #define BUILD_SCORE .1 1445 class CAI1Needs:CAIWant { 1446 CAnt *who; 1447 I32 request,final; 1448 }; 1449 Bool PathCostCb(CAI1Needs *poo,I64 x,I64 y) { 1450 I64 ox,oy; 1451 I64 c; 1452 for(ox=-1;ox<2;ox++) 1453 for(oy=-1;oy<2;oy++) { 1454 c=GrPeek(world.bitmap,x+ox,y+ox); 1455 //TODO check for enemy ants 1456 if(IsDirt(c)) { 1457 poo->time_cost+=1/3.; 1458 poo->dirt_cost--; 1459 } else if(IsEmpty(c)) { 1460 poo->time_cost+=1/10.; 1461 poo->dirt_cost++; 1462 } else 1463 poo->time_cost+=TILE_SZ/WORKER_SPEED*1.5; 1464 //Cant pass 1465 if(c==WORLD_ROCK1||c==WORLD_ROCK2) { 1466 return FALSE; 1467 } 1468 } 1469 return TRUE; 1470 } 1471 F64 AIAntDangerScore(CAntColony *colony,I64 x,I64 y) { 1472 F64 score=0.; 1473 I64 cnt,cnt2; 1474 CWorker *ant,*ant2; 1475 CAntColony *other,*head=&world.colonies; 1476 CAntCluster **clusters,*cluster; 1477 for(other=head->next;other!=head;other=other->next) { 1478 if(other!=colony) { 1479 clusters=GetAntClusters(other,&cnt); 1480 if(clusters) { 1481 while(--cnt>=0) { 1482 cluster=clusters[cnt]; 1483 if(AbsI64(cluster->cx-x)<=1&&AbsI64(cluster->cy-y)<=1) { 1484 cnt2=cluster->cnt; 1485 while(--cnt2>=0) { 1486 ant2=cluster->body[cnt2]; 1487 if(Sqrt(Sqr(ant2->position.y-y)+Sqr(ant2->position.x-x))<=8.) 1488 score++; 1489 } 1490 } 1491 Free(cluster); 1492 } 1493 Free(clusters); 1494 } 1495 } 1496 } 1497 return score; 1498 } 1499 //Get count of blocks for radius 1500 I64 AIDirtCntForRadius(I64 x,I64 y,I64 radius) { 1501 I64 ox,oy,c; 1502 I64 cnt=0; 1503 for(ox=-radius/2;ox<=radius/2;ox++) 1504 for(oy=-radius/2;oy<=radius/2;oy++) { 1505 c=GrPeek(world.bitmap,x+ox,y+oy); 1506 if(IsDirt(c)||IsGrass(c)) 1507 cnt++; 1508 } 1509 return cnt; 1510 } 1511 1512 U0 GenAntClusters(CAntColony *colony) { 1513 CAnt *ant,*head=&colony->ants; 1514 CDC *dc=DCNew(world.bitmap->width>>4,world.bitmap->height>>4); 1515 I64 x,y,c,cnt; 1516 I64 *sorted; 1517 CAntCluster **clusters,*cluster; 1518 DCFill(dc,0); 1519 for(ant=head->next;ant!=head;ant=ant->next) { 1520 //Add 1 to cluster 1521 dc->color=GrPeek(dc,x=ant->tile_x/16,y=ant->tile_y/16)+1; 1522 GrPlot(dc,x,y); 1523 } 1524 colony->cluster_cnt=0; 1525 for(x=0;x!=dc->width;x++) 1526 for(y=0;y!=dc->height;y++) { 1527 if(GrPeek(dc,x,y)) 1528 colony->cluster_cnt++; 1529 } 1530 clusters=MAlloc(colony->cluster_cnt*8,ant_task); 1531 cnt=0; 1532 for(x=0;x!=dc->width;x++) 1533 for(y=0;y!=dc->height;y++) { 1534 c=GrPeek(dc,x,y); 1535 if(c) { 1536 cluster=CAlloc(sizeof(CAntCluster)+8*c,ant_task); 1537 clusters[cnt++]=cluster; 1538 cluster->cnt=c; 1539 cluster->cx=x*16-8; 1540 cluster->cy=y*16-8; 1541 for(ant=head->next;ant!=head;ant=ant->next) { 1542 if(ant->tile_x/16==x&&ant->tile_y/16==y) { 1543 cluster->body[--c]=ant; 1544 if(c<=0) break; 1545 } 1546 } 1547 } 1548 } 1549 colony->clusters=clusters; 1550 } 1551 CAntCluster **GetAntClusters(CAntColony *c,I64 *cnt) { 1552 Bool unlock; 1553 CAntCluster **ret; 1554 I64 cnt2; 1555 if(!c->clusters) { 1556 if(cnt) *cnt=0; 1557 ret=NULL; 1558 goto fin; 1559 } 1560 ret=MAllocIdent(c->clusters); 1561 cnt2=c->cluster_cnt; 1562 if(cnt) *cnt=cnt2; 1563 while(--cnt2>=0) { 1564 ret[cnt2]=MAllocIdent(ret[cnt2]); 1565 } 1566 fin: 1567 return ret; 1568 } 1569 1570 CAnt *AntTouchesEnemy(CAntColony *c,CWorker *ant) { 1571 I64 cx=ant->tile_x/16,cy=ant->tile_y/16; 1572 I64 cnt,cnt2; 1573 CAnt *ret=NULL; 1574 CAntCluster **cl=GetAntClusters(c,&cnt),*clus; 1575 while(--cnt>=0) { 1576 clus=cl[cnt]; 1577 if(clus->cx==cx&&clus->cy==cy) { 1578 cnt2=clus->cnt; 1579 while(--cnt2>=0) 1580 if(clus->body[cnt2]->tile_x==ant->tile_x) 1581 if(clus->body[cnt2]->tile_y==ant->tile_y) 1582 ret=clus->body[cnt2]; 1583 } 1584 Free(clus); 1585 } 1586 Free(cl); 1587 return ret; 1588 } 1589 1590 1591 CAntCommand *NewPathCommand(I64 x,I64 y) { 1592 I64 c=GrPeek(world.bitmap,x,y); 1593 CAntCommand *ret=NULL; 1594 if(IsDirt(c)) { 1595 ret=CAlloc(sizeof(CAntCommand),ant_task); 1596 ret->insert_tS=tS; 1597 ret->x=x; 1598 ret->y=y; 1599 ret->type='Dig'; 1600 } else if(!IsEmpty(c)) { 1601 ret=CAlloc(sizeof(CAntCommand),ant_task); 1602 ret->insert_tS=tS; 1603 ret->x=x; 1604 ret->y=y; 1605 ret->type='Build'; 1606 } 1607 return ret; 1608 } 1609 1610 Bool _EnemyAI1MakePath(CAntColony *colony,CAI1Needs *needs,CAnt *ant,I64 x2,I64 y2,Bool dry=TRUE) { 1611 I64 ox=ant->tile_x,oy=ant->tile_y; 1612 I64 x_dist=x2-ox,y_dist=y2-oy; 1613 CAI1Needs needs0; 1614 I64 which_way=0; 1615 CAntCommand *new_com; 1616 MemCpy(&needs0,needs,sizeof CAI1Needs); 1617 I64 x=ox,y=oy; 1618 //Try x first,then y 1619 while(x!=x2) { 1620 x+=SignI64(x_dist); 1621 if(PathCostCb(&needs0,x,y)) { 1622 goto y_first; 1623 } 1624 } 1625 while(y!=y2) { 1626 y+=SignI64(y_dist); 1627 if(PathCostCb(&needs0,x,y)) { 1628 goto y_first; 1629 } 1630 } 1631 MemCpy(needs,&needs0,sizeof CAI1Needs); 1632 y=oy,x=ox; 1633 if(!dry) { 1634 QueDel(&ant->ai_commands); 1635 QueInit(&ant->ai_commands); 1636 while(x!=x2) { 1637 if(new_com=NewPathCommand(x,y)) 1638 QueIns(new_com,&ant->ai_commands); 1639 x+=SignI64(x_dist); 1640 } 1641 while(y!=y2) { 1642 if(new_com=NewPathCommand(x,y)) 1643 QueIns(new_com,&ant->ai_commands); 1644 y+=SignI64(y_dist); 1645 } 1646 } 1647 return TRUE; 1648 y_first: 1649 y=oy,x=ox; 1650 which_way=1; 1651 MemCpy(&needs0,needs,sizeof CAI1Needs); 1652 while(y!=y2) { 1653 y+=SignI64(y_dist); 1654 if(PathCostCb(&needs0,x,y)) { 1655 return FALSE; 1656 } 1657 } 1658 while(x!=x2) { 1659 x+=SignI64(x_dist); 1660 if(PathCostCb(&needs0,x,y)) { 1661 return FALSE; 1662 } 1663 } 1664 MemCpy(needs,&needs0,sizeof CAI1Needs); 1665 if(!dry) { 1666 QueDel(&ant->ai_commands); 1667 QueInit(&ant->ai_commands); 1668 y=oy,x=ox; 1669 while(y!=y2) { 1670 if(new_com=NewPathCommand(x,y)) 1671 QueIns(new_com,&ant->ai_commands); 1672 y+=SignI64(y_dist); 1673 } 1674 while(x!=x2) { 1675 if(new_com=NewPathCommand(x,y)) 1676 QueIns(new_com,&ant->ai_commands); 1677 x+=SignI64(x_dist); 1678 } 1679 } 1680 return TRUE; 1681 } 1682 U0 EnemyAI1MakePath(CAntColony *colony,CAI1Needs *needs,CAnt *who,I64 x2,I64 y2,Bool dry=TRUE) { 1683 CAnt dummy; 1684 CAI1Needs needs2; 1685 I64 inc=16,best_inc=16; 1686 CD3I64 pos; 1687 I64 best=I32_MAX,s; 1688 CAntCommand *wander_towards; 1689 MemCpy(&dummy,who,sizeof CAnt); 1690 while(inc<=64) { 1691 s=WanderTowardsPoint(&dummy,x2,y2,16); 1692 MemCpy(&needs2,needs,sizeof CAI1Needs); 1693 if(_EnemyAI1MakePath(colony,&needs2,&dummy,x2,y2,TRUE)) { 1694 s=needs2.time_cost+.75*TILE_SZ/WORKER_SPEED*pos.z; 1695 if(s>=best) { 1696 break; 1697 } 1698 } 1699 best=s; 1700 best_inc=inc; 1701 inc+=16; 1702 } 1703 if(best==I32_MAX) { 1704 needs->time_cost+=.75*TILE_SZ/WORKER_SPEED*best_inc; 1705 if(!dry) { 1706 wander_towards=CAlloc(sizeof(CAntCommand),ant_task); 1707 wander_towards->x=x2; 1708 wander_towards->y=y2; 1709 wander_towards->type='Move'; 1710 QueDel(&who->ai_commands); 1711 QueInit(&who->ai_commands); 1712 QueIns(wander_towards,&who->ai_commands); 1713 } 1714 } else { 1715 return _EnemyAI1MakePath(colony,needs,who,x2,y2,dry); 1716 } 1717 } 1718 1719 U0 EnemyAntAI1GetDirt(CAntColony *c,CAI1Needs *needs,CAnt *who,Bool dry=FALSE) { 1720 I64 cnt=AIDirtCntForRadius(who->tile_x,who->tile_y,18); //+2 as our clusters are 16 wide 1721 I64 got=0; 1722 I64 radius=2; 1723 I64 x=who->tile_x,y=who->tile_y,w,h; 1724 CAntCommand *cmd; 1725 if(!dry) { 1726 QueDel(&who->ai_commands); 1727 QueInit(&who->ai_commands); 1728 } 1729 while(radius<18) { 1730 for(w=-radius/2;w!=radius/2;w++) 1731 for(h=-radius/2;h!=radius/2;h++) { 1732 if(IsDirt(GrPeek(world.bitmap,x+w,y+h))) { 1733 needs->time_cost+=DIRT_SCORE; 1734 got++; 1735 if(!dry) { 1736 cmd=CAlloc(sizeof(CAntCommand),ant_task); 1737 cmd->type='Dig'; 1738 cmd->x=w+x; 1739 cmd->y=h+y; 1740 QueIns(cmd,&who->ai_commands); 1741 } 1742 } 1743 } 1744 radius+=2; 1745 } 1746 needs->dirt_cost-=got; 1747 } 1748 Bool ImposibleNeeds(CAI1Needs *needs) { 1749 if(needs->ant_cost<0.|| 1750 needs->dirt_cost<0.|| 1751 needs->food_cost<0.) 1752 return TRUE; 1753 return FALSE; 1754 } 1755 Bool EnemyAntAI1BirthAnt(CAntColony *c,CAI1Needs *needs,CAnt *queen,Bool is_queen=FALSE,Bool dry=FALSE) { 1756 if(!queen->is_queen) 1757 return FALSE; 1758 I64 cost=WORKER_COST; 1759 if(is_queen) 1760 cost=QUEEN_COST; 1761 if(is_queen) 1762 needs->ant_cost--; //We gain an ant 1763 else 1764 needs->ant_cost-=5; //We the capacity for lots more ants 1765 needs->food_cost+=cost; 1766 if(!dry&&c->food>=cost) { 1767 c->food-=cost; 1768 if(is_queen) 1769 NewQueenAnt(c,queen->tile_x,queen->tile_y); 1770 else 1771 NewWorkerAnt(c,queen->tile_x,queen->tile_y); 1772 } 1773 return FALSE; 1774 } 1775 Bool EnemyAntAI1GetFoodItem(CAntColony *c,CAI1Needs *needs,CAnt *who,CItem *want,Bool dry=TRUE) { 1776 CAI1Needs needs0,dummy; 1777 CAntCommand *cmd; 1778 MemCpy(&needs0,needs,sizeof(CAI1Needs)); 1779 EnemyAI1MakePath(c,&needs0,who,want->position.x,want->position.y,TRUE); 1780 needs0.time_cost+=1.25; //Assume 1/4 time needed to return to queen 1781 MemCpy(needs,&needs0,sizeof(CAI1Needs)); 1782 if(!dry) { 1783 QueDel(&who->ai_commands); 1784 QueInit(&who->ai_commands); 1785 MemCpy(&dummy,needs,sizeof(CAI1Needs)); 1786 EnemyAI1MakePath(c,&dummy,who,want->position.x,want->position.y,FALSE); 1787 cmd=CAlloc(sizeof(CAntCommand),ant_task); 1788 cmd->type='Eat'; 1789 cmd->insert_tS=tS; 1790 cmd->follow_item=want; 1791 QueIns(cmd,&who->ai_commands); 1792 } 1793 needs->food_cost-=want->user_data; 1794 return TRUE; 1795 } 1796 //Will Defend an area,simply move the cordnates to "chase enemy ants" 1797 Bool EnemyAntAIFight(CAntColony *c,CAI1Needs *needs,CAnt *who,CAnt *attack,Bool dry=TRUE) { 1798 CAI1Needs needs0,dummy; 1799 CAntCommand *cmd; 1800 EnemyAI1MakePath(c,&needs0,who,attack->tile_x,attack->tile_y,TRUE); 1801 if(!dry) { 1802 MemCpy(needs,&needs0,sizeof(CAI1Needs)); 1803 cmd=CAlloc(sizeof(CAntCommand),ant_task); 1804 cmd->type='Eat'; 1805 cmd->insert_tS=tS; 1806 cmd->follow_ant=attack; 1807 QueIns(cmd,&who->ai_commands); 1808 needs->ant_cost++; 1809 return TRUE; 1810 } 1811 return FALSE; 1812 } 1813 U0 EnemyAntAI1Think(CAntColony *colony,F64 alot_time=1/60.) { 1814 //Phase 1 generate needs 1815 //Phase 2 permutate needs/2 1816 F64 think_end_tS; 1817 I64 needs_ptr=0,icnt=QueCnt(&world.items),to,needs_cnt=0,idx,idx2; 1818 I64 action,rand; 1819 CAnt *ant1,dummy,*enemy; 1820 CItem *item; 1821 CAI1Needs final,final2; 1822 I64 cap=512; 1823 CAI1Needs *needs=CAlloc(sizeof(CAI1Needs)*cap),*need,*tmp=CAlloc(sizeof(CAI1Needs)*cap); 1824 I64 dry=TRUE; 1825 I64 acnt=QueCnt(&colony->ants); 1826 for(dry=TRUE;dry>=0;dry--) { 1827 needs_ptr=0; 1828 think_end_tS=tS+alot_time/2.; 1829 while(tS<think_end_tS) { 1830 //Phase 1 - Randomly generate commands for ants 1831 //Phase 2 - dry==FALSE,execute the commands for the ants 1832 for(ant1=colony->ants.next;ant1!=&colony->ants;ant1=ant1->next) { 1833 if(needs_ptr>=cap) 1834 goto end_phase1; 1835 need=&needs[needs_ptr++]; 1836 if(dry) { 1837 rand=RandU32; //Dont use U64 to avoid sign-bit 1838 } else if(!dry&&needs_cnt<=needs_ptr) { 1839 goto finish; 1840 } else if(!dry) { 1841 rand=need->request; 1842 } 1843 if(QueCnt(&ant1->ai_commands)) 1844 rand=-1; 1845 need->who=ant1; 1846 need->request=rand; 1847 if(ant1->is_queen) { 1848 switch(rand%5) { 1849 case 3: 1850 EnemyAntAI1BirthAnt(colony,need,ant1,TRUE,dry); 1851 break; 1852 case 4: 1853 EnemyAntAI1BirthAnt(colony,need,ant1,FALSE,dry); 1854 break; 1855 default: 1856 goto worker; 1857 } 1858 } else { 1859 worker: 1860 switch(rand%3) { 1861 case 0: 1862 //Do somthing with items 1863 to=RandU64%icnt; 1864 item=world.items.next; 1865 while(--to>=0) { 1866 item=item->next; 1867 } 1868 //Ensure we have food item 1869 if(item->ident=='Food') { 1870 EnemyAntAI1GetFoodItem(colony,need,ant1,item,dry); 1871 } else 1872 ; //TODO 1873 break; 1874 case 1: { //Attack enemy ants around homies 1875 if(AIAntDangerScore(colony,ant1->tile_x,ant1->tile_y)>1.) { 1876 //Check if we enemy ant is in walking distance 1877 MemCpy(&dummy,ant1,sizeof(CAnt)); 1878 to=8; 1879 while(--to>=0) { 1880 AntWanderNext(&dummy); 1881 if(enemy=AntTouchesEnemy(colony,&dummy)) { 1882 //Danger is within walking distance 1883 EnemyAntAIFight(colony,need,ant1,enemy,dry); 1884 break; 1885 } 1886 } 1887 } 1888 } 1889 break; 1890 case 2: //Get Dirt 1891 EnemyAntAI1GetDirt(colony,need,ant1,dry); 1892 break; 1893 } 1894 } 1895 } 1896 } 1897 end_phase1: 1898 if(!dry) { 1899 finish: 1900 Free(needs); 1901 Free(tmp); 1902 return; 1903 } 1904 cap=needs_ptr; 1905 think_end_tS=tS+alot_time/2.; //(think_end_tS-tS) is for leftover time 1906 MemSet(&final,0,sizeof(CAI1Needs)); 1907 action=0; 1908 while(tS<think_end_tS) { 1909 //Try commands and see what works 1910 final.dirt_cost=colony->dirt; 1911 final.food_cost=colony->food; 1912 final.ant_cost=QueCnt(&colony->ants); 1913 for(idx=0;idx<needs_ptr;idx++) { 1914 idx2=0; 1915 for(ant1=colony->ants.next;ant1!=&colony->ants;ant1=ant1->next) { 1916 need=&needs[idx]; 1917 MemCpy(&final2,&final,sizeof CAI1Needs); 1918 final2.ant_cost+=needs->ant_cost; 1919 final2.food_cost+=needs->food_cost; 1920 final2.dirt_cost+=needs->dirt_cost; 1921 final2.time_cost+=needs->time_cost; 1922 if(!ImposibleNeeds(&final2)) { 1923 MemCpy(&final,&final2,sizeof CAI1Needs); 1924 need->final=TRUE; 1925 MemCpy(tmp+action++,needs,sizeof CAI1Needs); 1926 if(action>=cap) goto end_phase2; 1927 } 1928 idx++; 1929 idx2++; 1930 } 1931 } 1932 } 1933 end_phase2:; 1934 needs_cnt=action; 1935 SwapI64(&tmp,&needs); 1936 } 1937 } 1938 U0 EnemyAI1(CAntColony *colony) { 1939 while(TRUE) { 1940 EnemyAntAI1Think(colony); 1941 Sleep(1000); 1942 } 1943 } 1944 // 1945 // Commands 1946 // 1947 // 1948 1949 <22>
//Build command 1950 //// 1951 //// 1952 //// 1953 //// 1954 1955 <23>
//Dig command 1956 //// 1957 //// 1958 //// 1959 //// 1960 <24>
//Eat command 1961 //// 1962 //// 1963 //// 1964 //// 1965 1966 U0 CommandControls(I64 m,I64 a1,I64 a2) { 1967 CD2 at; 1968 static Bool left=FALSE,right=FALSE; 1969 static F64 down_tS=0; 1970 CAntCommand *com; 1971 CItem *item; 1972 if(MSG_MS_R_DOWN==m) { 1973 down_tS=tS; 1974 right=TRUE; 1975 } else if(MSG_MS_R_UP==m) 1976 right=FALSE; 1977 else if(MSG_MS_L_DOWN==m) { 1978 down_tS=tS; 1979 left=TRUE; 1980 } else if(MSG_MS_L_UP==m) 1981 left=FALSE; 1982 else if(MSG_MS_MOVE==m) 1983 ; 1984 else 1985 return; 1986 //DEBUG PUT FOOD 1987 if(right) { 1988 ScrnCordsToWorldCoords(&at,a1,a2); 1989 a1=ToI64(at.x)/TILE_SZ; 1990 a2=ToI64(at.y)/TILE_SZ; 1991 world.bitmap->color=TRANSPARENT; 1992 GrPlot(world.bitmap,a1,a2); 1993 if(!ItemAtPos(a1,a2)) 1994 NewPieItem(a1,a2); 1995 } else if(left) { 1996 ScrnCordsToWorldCoords(&at,a1,a2); 1997 a1=at.x/TILE_SZ; 1998 a2=at.y/TILE_SZ; 1999 //Check for food item 2000 item=ItemAtPos(a1,a2); 2001 if(item) { 2002 if(item->ident=='Food') { 2003 com=CAlloc(sizeof(CAntCommand),ant_task); 2004 com->follow_item=item; 2005 com->type='Eat'; 2006 com->spr=<24>; 2007 com->insert_tS=down_tS; 2008 QueIns(com,&player_colony->commands); 2009 return; 2010 } 2011 } 2012 //Check if command already exists for corrdnate 2013 for(com=player_colony->commands.next;com!=&player_colony->commands;com=com->next) { 2014 if(com->x==a1&&com->y==a2) { 2015 if(com->insert_tS<down_tS) { 2016 QueRem(com); 2017 Free(com); 2018 } 2019 return; 2020 } 2021 } 2022 switch(GrPeek(world.bitmap,a1,a2)) { 2023 start: 2024 com=CAlloc(sizeof(CAntCommand),ant_task); 2025 com->x=a1; 2026 com->y=a2; 2027 com->insert_tS=down_tS; 2028 case WORLD_DIRT1: 2029 case WORLD_DIRT2: 2030 case WORLD_GRASS1: 2031 case WORLD_GRASS2: 2032 com->type='Dig'; 2033 com->spr=<23>; 2034 break; 2035 case WORLD_BLACK: 2036 case TRANSPARENT: 2037 com->type='Build'; 2038 com->spr=<22>; 2039 break; 2040 end: 2041 QueIns(com,&player_colony->commands); 2042 break; 2043 case WORLD_ROCK1: 2044 case WORLD_ROCK2: 2045 //Cant dig rocks 2046 break; 2047 case WORLD_WATER1: 2048 case WORLD_WATER2: 2049 case WORLD_WATER3: 2050 case WORLD_WATER4: 2051 //Buiild over water,not in it 2052 break; 2053 } 2054 } 2055 } 2056 2057 Bool ValidateItem(CItem *val) { 2058 if(!val) return FALSE; 2059 CItem *item; 2060 for(item=world.items.next;item!=&world.items;item=item->next) { 2061 if(item==val) return TRUE; 2062 } 2063 return FALSE; 2064 } 2065 2066 Bool ValidateAnt(CAnt *val) { 2067 if(!val) return FALSE; 2068 CAntColony *head1=world.colonies,*c; 2069 CAnt *head2,*a; 2070 for(c=head1->next;c!=head1;c=c->next) { 2071 head2=&c->ants; 2072 for(a=head2->next;a!=head2;a=a->next) 2073 if(a==val) 2074 return TRUE; 2075 } 2076 return FALSE; 2077 } 2078 2079 2080 U0 UpdateWorld() { 2081 CAntColony *colony; 2082 CWorker *ant; 2083 CItem *item; 2084 CQue *next; 2085 CAntCommand *com; 2086 for(colony=world.colonies.next;colony!=&world.colonies;colony=colony->next) { 2087 GenAntClusters(colony); 2088 for(com=colony->commands.next;com!=&colony->commands;com=next) { 2089 next=com->next; 2090 if(com->follow_item) { 2091 if(ValidateItem(com->follow_item)) { 2092 com->x=com->follow_item->position.x; 2093 com->y=com->follow_item->position.y; 2094 } else { 2095 QueRem(com); 2096 Free(com); 2097 } 2098 } else if(com->follow_ant) { 2099 if(ValidateAnt(com->follow_ant)) { 2100 com->x=com->follow_ant->tile_x; 2101 com->y=com->follow_ant->tile_y; 2102 } else { 2103 QueRem(com); 2104 Free(com); 2105 } 2106 } 2107 } 2108 for(ant=colony->ants.next;ant!=&colony->ants;ant=ant->next) { 2109 if(ant->carry) { 2110 if(!ValidateItem(ant->carry)) 2111 ant->carry=NULL; 2112 else { 2113 ant->carry->position.x=ant->tile_x; 2114 ant->carry->position.y=ant->tile_y; 2115 } 2116 } 2117 } 2118 } 2119 } 2120 2121 // 2122 // Test 2123 // 2124 <25>
2125 2126 2127 2128 2129 2130 2131 2132 QueInit(&world.colonies); 2133 QueInit(&world.items); 2134 WorldGen(256,64); 2135 world.cam_x=0; 2136 world.cam_y=0; 2137 world.cam_zoom=1.; 2138 U0 DrawIt(CTask *t,CDC *dc) { 2139 DrawWorld(dc,t); 2140 } 2141 2142 player_colony=NewColony(30,30,TRUE); 2143 CAntColony *ai_colony=NewColony(world.bitmap->width-30,30,TRUE); 2144 QueIns(player_colony,&world.colonies); 2145 QueIns(ai_colony,&world.colonies); 2146 U0 Main() { 2147 Spawn(&EnemyAI1,ai_colony,"AI Colony",-1,Fs); 2148 I64 a1,a2; 2149 I64 m; 2150 CD2 to; 2151 CD2I64 walk_towards; 2152 walk_towards.x=10; 2153 walk_towards.y=10; 2154 Fs->draw_it=&DrawIt; 2155 while(TRUE) { 2156 if(Bt(kbd.down_bitmap,SC_ESC)) 2157 break; 2158 2159 WorldCameraControl(m,a1,a2); 2160 while(m=ScanMsg(&a1,&a2)){ 2161 if(m==MSG_MS_MOVE) WorldCameraControl(m,a1,a2); 2162 CommandControls(m,a1,a2); 2163 } 2164 UpdateWorld; 2165 Refresh; 2166 } 2167 Fs->draw_it=NULL; 2168 } 2169 Main;