001 U0 ParsePersonality(U8 *file,U8 *who="AIPinWorm") { 002 U8 *f=FileRead(file); 003 CCmpCtrl *cc=CmpCtrlNew(f,,file); 004 Lex(cc); 005 CDoc *ai_fun_doc=DocNew; 006 DocPrint(ai_fun_doc,"U0 %s_AI(CGameThing *self) {\n",who); 007 I64 depth=0; 008 I64 s,e; 009 while(cc->token) { 010 if(cc->token==TK_IDENT) { 011 if(!StrCmp(cc->cur_str,"switch")) { 012 if(Lex(cc)!='(') 013 LexExcept(cc,"Expected a '(' at "); 014 Lex(cc); 015 if(cc->token==TK_IDENT) { 016 if(!cc->hash_entry) 017 goto expected_cond; 018 019 if(!(cc->hash_entry->type&HTT_FUN)) 020 goto expected_cond; 021 DocPrint(ai_fun_doc,"switch(.001+%s(self",cc->cur_str); 022 } else { 023 expected_cond:; 024 LexExcept(cc,"Expected condition function at "); 025 } 026 Lex(cc); 027 arg:; 028 if(cc->token!=')') { 029 if(cc->token==TK_STR) { 030 DocPrint(ai_fun_doc,",\"%Q\"",cc->cur_str); 031 Lex(cc); 032 goto arg; 033 } else { 034 DocPrint(ai_fun_doc,",%d",LexExpressionI64(cc)); 035 goto arg; 036 } 037 } 038 if(Lex(cc)!='{') 039 LexExcept(cc,"Expected a '{' at "); 040 Lex(cc); 041 DocPrint(ai_fun_doc,")) {\n$ID,2$"); 042 ++depth; 043 } else if(!StrCmp(cc->cur_str,"default")) { 044 if(':'!=Lex(cc)) 045 LexExcept(cc,"Expected a ':' "); 046 Lex(cc); 047 DocPrint(ai_fun_doc,"break;default:\n"); 048 } else if(!StrCmp(cc->cur_str,"case")) { 049 Lex(cc); 050 if(cc->token!=TK_I64) 051 LexExcept(cc,"Expected a percentage at "); 052 s=cc->cur_i64; 053 e=cc->cur_i64; 054 Lex(cc); 055 if(cc->token==TK_ELLIPSIS) { 056 if(Lex(cc)!=TK_I64); 057 LexExcept(cc,"Expected a percentage at "); 058 e=cc->cur_i64; 059 Lex(cc); 060 } 061 if(cc->token!=':') 062 LexExcept(cc,"Expected a ':' at "); 063 DocPrint(ai_fun_doc,"break;case %d ... %d:\n",s,e); 064 Lex(cc); 065 } else if(cc->hash_entry) { 066 if(!(cc->hash_entry->type&HTT_FUN)) { 067 if(cc->hash_entry->type&HTT_KEYWORD) 068 if(!StrCmp(cc->cur_str,"goto")) { 069 Lex(cc); 070 if(cc->token!=TK_IDENT) 071 LexExcept(cc,"Expected label at "); 072 DocPrint(ai_fun_doc,"goto %s;\n",cc->cur_str); 073 Lex(cc); 074 goto next; 075 } 076 goto label; 077 } 078 DocPrint(ai_fun_doc,"%s(self",cc->cur_str); 079 Lex(cc); 080 while(cc->token!=';') { 081 if(cc->token==TK_STR) { 082 DocPrint(ai_fun_doc,",\"%Q\"",cc->cur_str); 083 Lex(cc); 084 } else { 085 DocPrint(ai_fun_doc,",%d",LexExpressionI64(cc)); 086 } 087 } 088 DocPrint(ai_fun_doc,");\n"); 089 Lex(cc); 090 } else { 091 label:; 092 DocPrint(ai_fun_doc,"%s:\n",cc->cur_str); 093 if(Lex(cc)!=':') 094 LexExcept(cc,"Expected ':' at "); 095 Lex(cc); 096 } 097 } else if(cc->token=='}') { 098 if(!depth--) 099 LexExcept(cc,"Unexpected '}' at "); 100 DocPrint(ai_fun_doc,"$ID,-2$}\n"); 101 Lex(cc); 102 } else if(cc->token==';') 103 Lex(cc); 104 else 105 LexExcept(cc,"Unexpected token at "); 106 next:; 107 } 108 done:; 109 DocPrint(ai_fun_doc,"}\n"); 110 DocTop(ai_fun_doc); 111 DocInsDoc(DocPut,ai_fun_doc); 112 DocTop(ai_fun_doc); 113 ExeDoc(ai_fun_doc); 114 DocInsDoc(DocPut,ai_fun_doc); 115 DocDel(ai_fun_doc); 116 CmpCtrlDel(cc); 117 } 118 class CAIPinWorm:CPinWorm { 119 F64 next_path_find_tS; 120 }; 121 122 CPinWorm *SeekThing(CAIPinWorm *worm,U64 ident=PW_HEAD_IDENT) { 123 CAIPinWorm *head=&game.objects,*cur,*best=NULL; 124 CD3 ass; 125 F64 best_d=I16_MAX,d; 126 for(cur=head->qnext;cur!=head;cur=cur->qnext) { 127 if(cur->ident==ident&&worm!=cur) { 128 D3Sub(&ass,&cur->mass.x,&worm->mass.x); 129 if((d=D3Norm(&ass))<best_d) { 130 best_d=d; 131 best=cur; 132 } 133 } 134 135 } 136 return best; 137 } 138 139 140 // 141 // Conditions 142 // 143 F64 BurgerAround(CAIPinWorm *worm,F64 rad=300.) { 144 CI64Set *set=GetThingsOfTypeInRadius(worm->mass.x,worm->mass.y,rad,PW_BURGER_IDENT); 145 F64 per=set->cnt; 146 I64SetDel(set); 147 return per; 148 } 149 F64 EnemyAround(CAIPinWorm *worm,F64 rad=300.) { 150 CI64Set *set=GetThingsOfTypeInRadius(worm->mass.x,worm->mass.y,rad,PW_HEAD_IDENT); 151 F64 per=Max(set->cnt-1,0.); //TODO count enemy 152 I64SetDel(set); 153 return per; 154 } 155 F64 RocketAround(CAIPinWorm *worm,F64 rad=300.) { 156 CI64Set *set=GetThingsOfTypeInRadius(worm->mass.x,worm->mass.y,rad,PW_ROCKET_IDENT); 157 F64 per=0.; 158 I64 i; 159 CRocket *opp; 160 for(i=0;i!=set->cnt;++i) { 161 opp=set->body[i]; 162 if(opp->who_shot_rocket!=worm) 163 ++per; 164 } 165 I64SetDel(set); 166 return per; 167 } 168 F64 Health(CAIPinWorm *worm) { 169 return Max(worm->health,0.); 170 } 171 F64 CanSeeEnemy(CAIPinWorm *worm) { 172 CPinWorm *other=SeekThing(worm,PW_HEAD_IDENT); 173 if(!other) return other; 174 return CanSeeThing(worm,other); 175 176 } 177 // 178 // Actions 179 // 180 181 182 //May be a burger or a pinworm 183 Bool MoveTowards(CAIPinWorm *worm,CGameThing *t) { 184 F64 dx,dy,d,angle; 185 if(worm->next_path_find_tS>Game_tS) { 186 if(CanSeeThing(worm,t)) { 187 if(worm->path_finder_data) 188 I64SetDel(worm->path_finder_data); 189 worm->path_finder_data=NULL; 190 angle=worm->angle=Arg(dx=t->mass.x-worm->mass.x,dy=t->mass.y-worm->mass.y); 191 d=Sqrt(dx*dx+dy*dy); 192 worm->dx=Min(d,worm->stats.max_speed)*Cos(angle); 193 worm->dy=Min(d,worm->stats.max_speed)*Sin(angle); 194 return TRUE; 195 } 196 return FALSE; 197 } 198 worm->next_path_find_tS=Game_tS+1.5; 199 if(worm->path_finder_data) 200 I64SetDel(worm->path_finder_data); 201 worm->path_finder_data=PathFind(game.level,worm->mass.x,worm->mass.y,t->mass.x,t->mass.y); 202 return TRUE; 203 } 204 Bool Attack(CAIPinWorm *worm) { 205 CPinWorm *other=SeekThing(worm); 206 if(other) { 207 worm->angle=Arg(other->mass.x-worm->mass.x,other->mass.y-worm->mass.y); 208 PinWormFireRocket(worm); 209 return TRUE; 210 } 211 return FALSE; 212 } 213 Bool Die(CAIPinWorm *worm) { 214 PinWormDie(worm); 215 return TRUE; 216 } 217 Bool Chase(CAIPinWorm *worm) { 218 CPinWorm *other=SeekThing(worm); 219 if(!other) return FALSE; 220 MoveTowards(worm,other); 221 return TRUE; 222 } 223 Bool Say(CAIPinWorm *worm,...) { 224 U8 *str; 225 if(!argc) return FALSE; 226 str=argv[RandU64%argc]; 227 if(worm->chat_bot) { 228 ChatAdd(game.chat_log,str,worm->chat_bot); 229 } 230 } 231 Bool ChaseBurger(CAIPinWorm *worm) { 232 Bool has=FALSE; 233 CI64Set *burgers=GetThingsOfTypeInRadius(worm->mass.x,worm->mass.y,350.,PW_BURGER_IDENT); 234 CBurger *burger,*best=NULL; 235 CD3 ass; 236 F64 best_d=I16_MAX,d; 237 I64 i; 238 if(burgers->cnt) { 239 for(i=0;i!=burgers->cnt;++i) { 240 burger=burgers->body[i]; 241 D3Sub(&ass,&burger->mass.x,&worm->mass.x); 242 if((d=D3Norm(&ass))<best_d) { 243 best=burger; 244 } 245 } 246 if(best) { 247 MoveTowards(worm,best); 248 has=TRUE; 249 } 250 } 251 I64SetDel(burgers); 252 return has; 253 } 254 Bool Evade(CAIPinWorm *worm) { 255 F64 x,y; 256 I64 i,i2; 257 F64 rdx,rdy; 258 F64 angle,dot; 259 Bool evaded=FALSE; 260 Bool close=FALSE; 261 CI64Set *rockets=GetThingsOfTypeInRadius(x=worm->mass.x,y=worm->mass.y,350.,PW_ROCKET_IDENT); 262 CRocket *r; 263 for(i=0;i!=rockets->cnt;++i) { 264 r=rockets->body[i]; 265 if(r->who_shot_rocket!=worm) { 266 rdx=r->mass.DxDt; 267 rdy=r->mass.DyDt; 268 //Check if missile is oppsite direction of worm(Dot Product 21). 269 dot=rdx*worm->mass.DxDt+rdy*worm->mass.DyDt; 270 if(dot>0.) { 271 close=Sqrt(Sqr(worm->mass.x-r->mass.x)+Sqr(worm->mass.y-r->mass.y))<160.; 272 angle=Arg(rdx,rdy); 273 //Try to go opposite side of rocket 274 if(rdx*(worm->mass.y-r->mass.y)>rdy*(worm->mass.x-r->mass.x)) { 275 if(close) 276 angle+=pi/2; //to side 277 else 278 angle+=pi/4; 279 280 } else { 281 if(close) 282 angle-=pi/2; //to side 283 else 284 angle-=pi/4; 285 } 286 287 worm->dx=Cos(angle)*worm->stats.max_speed; 288 worm->dy=Sin(angle)*worm->stats.max_speed; 289 worm->angle=angle; 290 evaded=TRUE; 291 } 292 } 293 } 294 I64SetDel(rockets); 295 return evaded; 296 } 297 U0 AIPinWorm_AI(CAIPinWorm *worm) { 298 //Weight out outcomes or somthin 299 F64 now=Game_tS; 300 F64 last_attack=worm->last_rocket_tS; 301 F64 next_attack=last_attack+1./worm->stats.max_rockets; 302 ChaseBurger(worm); 303 if(now>next_attack) 304 Attack(worm); 305 if(!Evade(worm)) { 306 if(worm->path_finder_data&&worm->path_finder_data->cnt) { 307 PathFinderGo(game.level,worm->path_finder_data,10.,50.,&worm->mass.x,&worm->dx); 308 PinWormUnStuck(worm); 309 } 310 } 311 worm->obj->rot=worm->angle; 312 } 313 ParsePersonality("AssHole_AI.HC","AIPinWorm");