0001 #include "GarbageCollector"; 0002 CTask *mem_task=Fs; 0003 F64 Game_tS() { 0004 return tS; 0005 } 0006 extern U0 ThingDel(U64 *w,Bool hard=TRUE); 0007 extern U0 LockWorld(); 0008 extern U0 UnlockWorld(); 0009 extern U8 *RocketChooseTarget(U8 *r); 0010 #include "Skeletal"; 0011 #include "LevelEditor"; 0012 #include "Matrix4x4Inv"; 0013 #include "AStar"; 0014 #include "Chat"; 0015 #include "UI"; 0016 #include "MeshMakers"; 0017 C2DWorld *world=C2DWorldNew(BLACK); 0018 I64 ms_x=0,ms_y=0; 0019 0020 U8 *pinworm_body_mesh; 0021 U8 *pinworm_head_mesh; 0022 U8 *rocket_mesh; 0023 0024 U8 *burger_mesh; 0025 0026 U0 InitMeshes() { 0027 I64 mat[16],step; 0028 //Food 0029 U8 *bun_top,*bun_bottom,*tmp; 0030 bun_bottom=PrimitiveCylinder3D(30,-10.); 0031 bun_top=PrimitiveCone3D(30,10); 0032 Mat4x4IdentEqu(mat); 0033 Mat4x4TranslationEqu(mat,0,0,15); 0034 burger_mesh=CD6Merge(bun_bottom,bun_top,mat); 0035 CD6SetColor(burger_mesh,YELLOW); 0036 tmp=PrimitiveRect3D(50,50,15); 0037 CD6SetColor(tmp,LTPURPLE); 0038 Mat4x4IdentEqu(mat); 0039 Mat4x4TranslationEqu(mat,0,0,15/2); 0040 bun_top=CD6Merge(burger_mesh,tmp,mat); 0041 Mat4x4IdentEqu(mat); 0042 Mat4x4PointTo(mat,0,-50,0); 0043 Mat4x4Scale(mat,1); 0044 burger_mesh=CD6NewTransform(bun_top,mat); 0045 0046 0047 //Pinworm head 0048 pinworm_body_mesh=PrimitiveSphere3D(30./2,pi/3); 0049 U8 *head=PrimitiveRect3D(50,50,50),*body; 0050 U8 *horn=PrimitiveCone3D(10,50,pi/3),*thruster; 0051 Mat4x4IdentEqu(mat); 0052 Mat4x4TranslationEqu(mat,25,-25,0); 0053 Mat4x4PointTo(mat,50,-50,0); 0054 pinworm_head_mesh=CD6Merge(head,horn,mat); 0055 Mat4x4IdentEqu(mat); 0056 Mat4x4TranslationEqu(mat,25,25,0); 0057 Mat4x4PointTo(mat,50,50,0); 0058 pinworm_head_mesh=CD6Merge(pinworm_head_mesh,horn,mat); 0059 //Rcoket 0060 Mat4x4IdentEqu(mat); 0061 body=PrimitiveCylinder3D(30,60); 0062 head=PrimitiveCone3D(30,50); 0063 Mat4x4TranslationEqu(mat,0,0,60); 0064 tmp=CD6Merge(body,head,mat); 0065 body=tmp; 0066 //Make thrusters on rocket 0067 thruster=PrimitiveCylinder3D(15,45); 0068 for(step=0;step!=2;step++) { 0069 Mat4x4IdentEqu(mat); 0070 Mat4x4TranslationEqu(mat,15*Cos(step*pi),15*Sin(step*pi),-45); 0071 tmp=CD6Merge(body,thruster,mat); 0072 body=tmp; 0073 } 0074 Mat4x4IdentEqu(mat); 0075 Mat4x4RotY(mat,-pi/2); 0076 rocket_mesh=CD6NewTransform(body,mat); 0077 }; 0078 InitMeshes; 0079 0080 0081 #define PW_BODY_IDENT 'PWBody' 0082 #define PW_HEAD_IDENT 'PWHead' 0083 #define PW_ROCKET_IDENT 'GNRckt' 0084 #define PW_GUN_IDENT 'GNGun' 0085 #define PW_EXPLODE_IDENT 'EXExpd' 0086 #define PW_BURGER_IDENT 'Burger' 0087 0088 #define PW_MAX_DIST 30 0089 #define PW_LINK_ANGLE (pi/4) 0090 0091 #define FRICTION .965 0092 0093 class CWormStats { 0094 I64 rocket_mass; 0095 I64 max_rockets; 0096 F64 max_speed; 0097 F64 max_health; 0098 }; 0099 0100 #define WSTATS_F_ROCKET_MASS 1 0101 #define WSTATS_F_MAX_ROCKETS 2 0102 #define WSTATS_F_MAX_SPEED 4 0103 #define WSTATS_F_MAX_HEALTH 8 0104 0105 U0 WormStatsInit(CWormStats *stats) { 0106 stats->rocket_mass=50; 0107 stats->max_rockets=1.; 0108 stats->max_speed=50; 0109 stats->max_health=100.; 0110 } 0111 0112 U0 WormStatsLevelUp(CWormStats *stats,I64 flags,I64 level=1) { 0113 if(flags&WSTATS_F_MAX_SPEED) 0114 stats->max_speed+=level*15.; 0115 if(flags&WSTATS_F_MAX_HEALTH) 0116 stats->max_health+=level*50.; 0117 if(flags&WSTATS_F_MAX_ROCKETS) 0118 stats->max_rockets+=level; 0119 if(flags&WSTATS_F_ROCKET_MASS) 0120 stats->rocket_mass+=level; 0121 } 0122 extern class CPinWormBody; 0123 class CMass2:CMass { 0124 CPinWormBody *who; 0125 COrder2D3 dummy,dummy2; 0126 }; 0127 class CSpring2:CSpring { 0128 F64 strength; //Froce before snapping. 0129 }; 0130 #define THINGF_TO_DELETE 1 0131 #define THINGF_EXPLODED 2 0132 #define THINGF_DAMAGED 4 0133 #define THINGF_HIT_LINE 8 0134 #define THINGF_HIT_THING 16 0135 class CGameThing { 0136 CThing *qnext,*qlast; 0137 U64 ident; 0138 U64 flags; 0139 C2DObject *obj; 0140 CMass old_mass; 0141 F64 health,food; 0142 CMass2 mass; 0143 CI64Set *path_finder_data; //CMove 0144 F64 dx,dy,dz; //From player 0145 F64 dx2,dy2,dz2; //from explosions n stuff 0146 CGameThing *hit_thing; 0147 U0 (*animate)(CGameThing *,...); 0148 U0 (*collide_thing)(CGameThing *,...); 0149 U0 (*collide_line)(CGameThing *,...); 0150 U0 (*damage)(CGameThing *,...); 0151 U0 (*ai)(CGameThing *); 0152 } 0153 0154 class CPinWormBody:CGameThing { 0155 CSpring2 spring; 0156 F64 angle; 0157 CPinWormBody *next; 0158 CPinWormBody *parent; 0159 }; 0160 class CPinWorm:CPinWormBody { 0161 CWormStats stats; 0162 F64 last_rocket_tS; 0163 CBot *chat_bot; 0164 F64 spawn_at_x,spawn_at_y; 0165 F64 look_at_x,look_at_y; 0166 //Player 0167 CUIBigText *health_meter; 0168 CUIBigText *food_meter; 0169 CUITree *menu; 0170 CUIGrid *hotbar; 0171 }; 0172 class CRocket:CGameThing { 0173 CMass2 mass2; 0174 CSpring2 spring; 0175 CGameThing *who_shot_rocket; 0176 F64 explosion_force; 0177 }; 0178 class CGun:CGameThing { 0179 F64 last_fire; 0180 F64 max; 0181 }; 0182 class CBurger:CGameThing { 0183 F64 amt; 0184 }; 0185 class CGame { 0186 CQue objects; 0187 CLevel *level; 0188 CD3 camera_center; 0189 CQue particles; 0190 F64 camera_height; 0191 CChat *chat_log; 0192 I64 locked_flags; 0193 CUIRoot *game_ui; 0194 } game; 0195 class CExplosion:CGameThing { 0196 CGameThing *from; 0197 F64 start_tS; 0198 F64 duration; 0199 F64 force; 0200 //Private 0201 F64 rad; 0202 }; 0203 CPinWorm *player_worm; 0204 U0 ThingActionExplode(CGameThing *thing,...) { 0205 thing->flags|=THINGF_EXPLODED; 0206 ThingDel(thing,FALSE); 0207 } 0208 Bool ThingIsStuck(CGameThing *thing,F64 fudge=1./10.) { 0209 CD3 tmp; 0210 F64 expected; 0211 D3Sub(&tmp,&thing->mass.x,&thing->old_mass.x); 0212 expected=D3Norm(&thing->dx); 0213 return D3Norm(&tmp)<expected*fudge; 0214 } 0215 U0 ComputeExplosionRadius(CExplosion *exp) { 0216 F64 rad=(Game_tS-exp->start_tS)/2./exp->duration; 0217 if(rad>.5) { 0218 rad=exp->force-exp->force*((rad-.5)*2)+2.; 0219 } else { 0220 rad=rad*exp->force*2; 0221 } 0222 exp->rad=Max(rad,1.); 0223 exp->mass.mass=exp->rad; 0224 } 0225 U0 DrawExplosion(CExplosion *exp,CDC *dc) { 0226 ComputeExplosionRadius(exp); 0227 F64 rad=exp->rad; 0228 I64 which; 0229 if(rad<=1.1) { 0230 exp->flags|=THINGF_TO_DELETE; 0231 return; 0232 } 0233 dc->thick=1; 0234 for(which=1;which<rad;++which) { 0235 dc->color=7+RandU64&7; 0236 GrCircle3(dc,exp->mass.x,exp->mass.y,0,which); 0237 } 0238 } 0239 0240 #include "Particles"; 0241 CI64Set *GetThingsInRadius(F64 x,F64 y,F64 rad) { 0242 CI64Set *ret=I64SetNew; 0243 //TODO something better 0244 CGameThing *head=&game.objects,*t; 0245 for(t=head->qnext;head!=t;t=t->qnext) { 0246 if(Sqr(t->mass.x-x)+Sqr(t->mass.y-y)<rad*rad) 0247 I64SetAdd(ret,t); 0248 } 0249 return ret; 0250 } 0251 U0 DamageThing(CGameThing *t,F64 d) { 0252 t->health-=d; 0253 t->flags|=THINGF_DAMAGED; 0254 } 0255 0256 U0 AddMass(CMass2 *m) { 0257 LockWorld; 0258 QueIns(m,mem_task->last_ode->last_mass); 0259 UnlockWorld; 0260 } 0261 0262 CExplosion *ExplosionNew(F64 x,F64 y,CGameThing *from=NULL,F64 force=200.,F64 damage_percent=1/10.) { 0263 CExplosion *exp=GCCAlloc(sizeof(CExplosion)); 0264 I64 cnt; 0265 CD3 tmp,at; 0266 F64 d; 0267 CI64Set *around=GetThingsInRadius(x,y,force); 0268 CGameThing *gt; 0269 exp->ident=PW_EXPLODE_IDENT; 0270 exp->from=from; 0271 exp->mass.x=x; 0272 exp->mass.y=y; 0273 exp->mass.mass=1; 0274 exp->mass.who=exp; 0275 exp->start_tS=Game_tS; 0276 exp->duration=1.; 0277 exp->force=200; 0278 AddMass(&exp->mass); 0279 QueIns(&exp->qnext,&game.objects); 0280 //Particles 0281 for(cnt=0;cnt!=21;cnt++) { 0282 ParticleNew(x,y,Rand*2*pi,15*Rand+15); 0283 } 0284 0285 ClipRect(game.level,x-force/2.,y-force/2.,x+force/2.,y+force/2.); 0286 0287 at.x=x; 0288 at.y=y; 0289 at.z=0; 0290 for(cnt=0;cnt!=around->cnt;++cnt) { 0291 gt=around->body[cnt]; 0292 D3Sub(&tmp,>->mass.x,&at); 0293 d=D3Norm(&tmp); 0294 if(d<force-10.) { 0295 d+=10.; 0296 d=force-d; 0297 D3MulEqu(&tmp,d*.5); 0298 D3AddEqu(>->dx2,&tmp); 0299 if(from!=gt) 0300 DamageThing(gt,d*damage_percent); 0301 } 0302 } 0303 0304 I64SetDel(around); 0305 Noise(250,50,80); 0306 return exp; 0307 } 0308 CPinWormBody *PinWormBodyNew(CPinWorm *worm) { 0309 F64 x;F64 y; 0310 CPinWormBody *body=GCCAlloc(sizeof(CPinWormBody)),*next; 0311 CMass *mass; 0312 CPinWorm *me=worm; 0313 again:; 0314 if(worm->ident==PW_HEAD_IDENT) { 0315 mass=&worm->mass; 0316 next=worm->next; 0317 x=worm->mass.x; 0318 y=worm->mass.y; 0319 } else if(worm->ident==PW_BODY_IDENT) { 0320 mass=&worm(CPinWormBody*)->mass; 0321 next=worm(CPinWormBody*)->next; 0322 x=worm(CPinWormBody*)->mass.x; 0323 y=worm(CPinWormBody*)->mass.y; 0324 } 0325 if(next) { 0326 worm=next; 0327 goto again; 0328 } 0329 body->parent=worm; 0330 worm(CPinWormBody*)->next=body; 0331 body->health=100; 0332 body->ident=PW_BODY_IDENT; 0333 body->mass.who=body; 0334 body->mass.x=x; 0335 body->mass.y=y; 0336 body->mass.mass=PW_MAX_DIST; 0337 AddMass(&body->mass); 0338 body->spring.const=1e5; 0339 body->spring.end2=&body->mass; 0340 body->spring.end1=mass; 0341 body->spring.flags=SSF_NO_COMPRESSION; 0342 body->spring.rest_len=25.; 0343 QueIns(&body->spring,Fs->last_ode->last_spring); 0344 QueIns(&body->qnext,&game.objects); 0345 body->obj=C2DObjectNewFromMesh(pinworm_body_mesh); 0346 body->obj->color=WHITE; 0347 AddObjectToWorld(body->obj,world); 0348 body->next=next; 0349 return body; 0350 } 0351 0352 0353 CPinWorm *PinWormNew(F64 x,F64 y) { 0354 CPinWorm *pw=GCCAlloc(sizeof(CPinWorm)); 0355 pw->health=100; 0356 pw->ident=PW_HEAD_IDENT; 0357 pw->mass.x=x; 0358 pw->mass.y=y; 0359 pw->mass.mass=50.; 0360 pw->mass.who=pw; 0361 AddMass(&pw->mass); 0362 QueIns(&pw->qnext,&game.objects); 0363 pw->obj=C2DObjectNewFromMesh(pinworm_head_mesh); 0364 AddObjectToWorld(pw->obj,world); 0365 WormStatsInit(&pw->stats); 0366 return pw; 0367 } 0368 0369 0370 CBurger *BurgerNew(F64 x,F64 y) { 0371 CBurger *pw=GCCAlloc(sizeof(CPinWorm)); 0372 pw->ident=PW_BURGER_IDENT; 0373 pw->mass.x=x; 0374 pw->mass.y=y; 0375 pw->mass.mass=30.; 0376 pw->mass.who=pw; 0377 AddMass(&pw->mass); 0378 QueIns(&pw->qnext,&game.objects); 0379 pw->obj=C2DObjectNewFromMesh(burger_mesh); 0380 AddObjectToWorld(pw->obj,world); 0381 return pw; 0382 } 0383 0384 #include "Weapons/Green"; 0385 #include "Weapons/Builder"; 0386 U0 RocketCollideThing(CRocket *r,...) { 0387 CGameThing *other=argv[0]; 0388 if(other!=r&&other!=r->who_shot_rocket) 0389 ThingActionExplode(r); 0390 } 0391 U0 RocketAI(CRocket *r) { 0392 CGameThing *target=RocketChooseTarget(r); 0393 F64 force=Max(20.*30.,D3Norm(&r->mass.DxDt)),angle; 0394 if(target) { 0395 angle=Arg(target->mass.x-r->mass.x,target->mass.y-r->mass.y); 0396 r->mass.DxDt=force*Cos(angle); 0397 r->mass.DyDt=force*Sin(angle); 0398 } 0399 } 0400 U0 RocketNew(F64 x,F64 y,F64 angle=0,F64 force=200.,CGameThing *who_shot=NULL) { 0401 CRocket *rocketb=GCCAlloc(sizeof(CRocket)); 0402 rocketb->collide_line=&ThingActionExplode; 0403 rocketb->collide_thing=&RocketCollideThing; 0404 rocketb->ai=&RocketAI; 0405 rocketb->ident=PW_ROCKET_IDENT; 0406 rocketb->mass.x=x+30*Cos(angle); 0407 rocketb->mass.y=y+30*Sin(angle); 0408 rocketb->mass.mass=50; 0409 rocketb->mass.who=rocketb; 0410 rocketb->mass2.x=x+60*Cos(angle); 0411 rocketb->mass2.y=y+60*Sin(angle); 0412 rocketb->mass2.mass=25; 0413 rocketb->mass2.who=rocketb; 0414 rocketb->spring.end2=&rocketb->mass; 0415 rocketb->spring.end1=&rocketb->mass2; 0416 rocketb->spring.strength=10000; 0417 rocketb->spring.const=100.; 0418 rocketb->spring.rest_len=30.; 0419 rocketb->explosion_force=force; 0420 rocketb->who_shot_rocket=who_shot; 0421 rocketb->mass.DxDt=25*Cos(angle)*30; 0422 rocketb->mass.DyDt=25*Sin(angle)*30; 0423 rocketb->mass2.DxDt=25*Cos(angle)*30; 0424 rocketb->mass2.DyDt=25*Sin(angle)*30; 0425 0426 AddMass(&rocketb->mass); 0427 AddMass(&rocketb->mass2); 0428 QueIns(&rocketb->spring,Fs->last_ode->last_spring); 0429 0430 QueIns(&rocketb->qnext,&game.objects); 0431 0432 rocketb->obj=C2DObjectNewFromMesh(rocket_mesh); 0433 // rocketb->obj=C2DObjectNewFromMesh(MakeSpawnerMesh(RED)); 0434 rocketb->obj->color=LTRED; 0435 AddObjectToWorld(rocketb->obj,world); 0436 return rocketb; 0437 } 0438 0439 U0 PinWormFireRocket(CPinWorm *pw) { 0440 if(pw->last_rocket_tS+1./pw->stats.max_rockets>Game_tS) 0441 return; 0442 pw->last_rocket_tS=Game_tS; 0443 Sweep(250,70,50); 0444 RocketNew(pw->mass.x, 0445 pw->mass.y, 0446 pw->angle, 0447 200., 0448 pw 0449 ); 0450 } 0451 U0 PinWormFireGreen(CPinWorm *pw) { 0452 } 0453 U0 PinWormFireBuildWall(CPinWorm *pw) { 0454 if(pw->last_rocket_tS+.5>Game_tS) 0455 return; 0456 pw->last_rocket_tS=Game_tS; 0457 Sweep(250,70,50); 0458 0459 BuildWallFire(pw->look_at_x, 0460 pw->look_at_y, 0461 pw 0462 ); 0463 } 0464 0465 0466 Bool CanSeeThing(CGameThing *a,CGameThing *b) { 0467 F64 dist=Sqrt(Sqr(b->mass.y-a->mass.y)+Sqr(b->mass.x-a->mass.x)); 0468 return MaxMoveDist(game.level,a->mass.x,a->mass.y,b->mass.x,b->mass.y)>dist; 0469 } 0470 0471 0472 U0 PinWormUnStuck(CPinWorm *pw) { 0473 CPinWormBody *body; 0474 if(ThingIsStuck(pw)) { 0475 body=pw->next; 0476 while(body&&CanSeeThing(pw,body)) { 0477 body=body->next; 0478 } 0479 //Cant see this pinworm body,fire a rocket at the wall(blocking the pinworm body) 0480 if(body) { 0481 pw->angle=Arg(body->mass.x-pw->mass.x,body->mass.y-pw->mass.y); 0482 PinWormFireRocket(pw); 0483 } 0484 } 0485 } 0486 0487 CPinWorm *BelongsTo(CPinWormBody *b) { 0488 while(b&&b->ident==PW_BODY_IDENT) 0489 b=b->parent; 0490 return b; 0491 } 0492 CPinWormBody *RocketChooseTarget(CRocket *r) { 0493 CGameThing *ignore=r->who_shot_rocket; 0494 CPinWormBody *body,*best=NULL,*head; 0495 I64 idx; 0496 F64 best_dist=I16_MAX*I16_MAX,dist; 0497 CD3 tmp; 0498 0499 CI64Set *things=GetThingsInRadius(r->mass.x,r->mass.y,5000); 0500 for(idx=0;idx!=things->cnt;++idx) { 0501 body=things->body[idx]; 0502 if(body->ident==PW_HEAD_IDENT||body->ident==PW_BODY_IDENT) { 0503 head=BelongsTo(body); 0504 if(head!=r->who_shot_rocket) 0505 if(r!=body) { //&&CanSeeThing(r,body) 0506 D3Sub(&tmp,&r->mass.x,&body->mass.x); 0507 dist=D3Norm(&tmp); 0508 if(dist<best_dist) { 0509 best_dist=dist; 0510 best=body; 0511 } 0512 } 0513 } 0514 } 0515 return best; 0516 } 0517 U0 ThingDel(U64 *w,Bool hard=TRUE) { 0518 if(!w) return; 0519 CPinWorm *pw; 0520 CPinWormBody *body; 0521 CGun *g; 0522 CRocket *rocket; 0523 pw=w; 0524 if(!hard) { 0525 pw=w; 0526 pw->flags|=THINGF_TO_DELETE; 0527 return ; 0528 } 0529 LockWorld; 0530 if(pw->path_finder_data) 0531 I64SetDel(pw->path_finder_data); 0532 if(w[2]==PW_GUN_IDENT) { 0533 g=w; 0534 C2DObjectDel(g->obj); 0535 QueRem(&g->mass); 0536 QueRem(g); 0537 ret: 0538 UnlockWorld; 0539 return; 0540 } 0541 if(w[2]==PW_ROCKET_IDENT) { 0542 rocket=w; 0543 C2DObjectDel(rocket->obj); 0544 QueRem(&rocket->mass); 0545 QueRem(&rocket->mass2); 0546 QueRem(&rocket->spring); 0547 QueRem(rocket); 0548 goto ret; 0549 } 0550 if(w[2]==PW_HEAD_IDENT) { 0551 pw=w; 0552 ThingDel(pw->next,FALSE); 0553 if(pw->chat_bot) 0554 BotDel(pw->chat_bot); 0555 C2DObjectDel(pw->obj); 0556 QueRem(&pw->mass); 0557 QueRem(&pw->qnext); 0558 goto ret; 0559 } 0560 if(w[2]==PW_GREEN_SHOT_IDENT) { 0561 body=w; 0562 C2DObjectDel(body->obj); 0563 QueRem(&body->mass); 0564 QueRem(body); 0565 goto ret; 0566 } 0567 if(w[2]==PW_BODY_IDENT) { 0568 body=w; 0569 ThingDel(body->next,FALSE); 0570 C2DObjectDel(body->obj); 0571 //Remove both ends,QueInit to allow re-QueRem 0572 QueRem(body->spring.end1); 0573 QueInit(body->spring.end1); 0574 //Ditto 0575 QueRem(body->spring.end2); 0576 QueInit(body->spring.end2); 0577 0578 QueRem(&body->spring); 0579 QueRem(&body->qnext); 0580 QueRem(&body->mass); 0581 goto ret; 0582 } 0583 if(w[2]==PW_BURGER_IDENT) { 0584 pw=w; 0585 C2DObjectDel(pw->obj); 0586 QueRem(&pw->qnext); 0587 QueRem(&pw->mass); 0588 goto ret; 0589 } 0590 // 0591 pw=w; 0592 QueRem(&pw->mass); 0593 QueRem(w); 0594 GCFree(w); 0595 goto ret; 0596 } 0597 U0 UpdateWorldMatrix() { 0598 CDC *scrn=world->scrn; 0599 Mat4x4IdentEqu(scrn->r); 0600 Mat4x4TranslationEqu(scrn->r, 0601 -game.camera_center.x, 0602 -game.camera_center.y, 0603 300+game.camera_center.z+game.camera_height); 0604 } 0605 0606 0607 #include "StarBG.HC"; 0608 U0 DrawStarsBG(CDC *d) { 0609 I64 xoff,yoff,x,y,cx=game.camera_center.x,cy=game.camera_center.y; 0610 d->color=WHITE; 0611 d->thick=4; 0612 for(xoff=cx-1024;xoff<=cx+1024;xoff+=STAR_SPACING) { 0613 for(yoff=cy-1024;yoff<=cy+1024;yoff+=STAR_SPACING) { 0614 x=xoff,y=yoff; 0615 if(Star(&x,&y)) { 0616 GrPlot3(d,x,y,1); 0617 } 0618 } 0619 } 0620 0621 } 0622 0623 U0 PinWormDrawIt(CTask *t,CDC *d) { 0624 LockWorld; 0625 if(player_worm) { 0626 game.camera_center.x=player_worm->mass.x; 0627 game.camera_center.y=player_worm->mass.y; 0628 } 0629 CPinWorm *pw; 0630 CPinWormBody *body; 0631 CLine *line,*head; 0632 CRocket *r; 0633 CNode *st,*en; 0634 CDC *scrn=world->scrn; 0635 I64 chat_w=LOG_WIDTH*8,chat_h=LOG_SZ*8; 0636 I64 chat_x=t->pix_width-chat_w-20,chat_y=20; 0637 UpdateWorldMatrix; 0638 for(pw=game.objects.next;pw!=&game.objects;pw=pw->qnext) { 0639 if(pw->obj) 0640 C2DObjectMove(pw->obj,pw->mass.x,pw->mass.y); 0641 if(pw->ident==PW_ROCKET_IDENT) { 0642 r=pw; 0643 C2DObjectRotate(pw->obj, 0644 Arg(r->mass.x-r->mass2.x,r->mass.y-r->mass2.y) 0645 ); 0646 } 0647 } 0648 DrawWorld(t,world); 0649 DrawStarsBG(world->scrn); 0650 DrawParticles(world->scrn); 0651 for(pw=game.objects.next;pw!=&game.objects;pw=pw->qnext) { 0652 if(pw->ident==PW_EXPLODE_IDENT) 0653 DrawExplosion(pw,world->scrn); 0654 } 0655 if(game.level) { 0656 head=&game.level->lines; 0657 for(line=head->next;line!=head;line=line->next) { 0658 scrn->color=WHITE; 0659 scrn->thick=3; 0660 st=line->start; 0661 en=line->end; 0662 GrLine3(scrn,st->x,st->y,0,en->x,en->y,0); 0663 0664 } 0665 } 0666 GrBlot(d,0,0,world->scrn); 0667 DrawUI(t,d); 0668 ChatDraw(d,chat_x,chat_y,game.chat_log); 0669 UnlockWorld; 0670 } 0671 F64 LineDist(CD3 *a,CD3 *b,CD3 *pt,CD3 *hit_at=NULL) { 0672 CD3 rel_pt; 0673 CD3 rel_b; 0674 CD3 from; 0675 D3Sub(&rel_pt,pt,a); 0676 D3Sub(&rel_b,b,a); 0677 <1>0678 0679 0680 0681 0682 F64 rel=D3Dot(&rel_pt,&rel_b)/D3Dot(&rel_b,&rel_b); 0683 if(0.<=rel<=1.) { 0684 from.x=a->x+rel_b.x*rel; 0685 from.y=a->y+rel_b.y*rel; 0686 from.z=0; 0687 } else if(rel<0.) { 0688 D3Equ(&from,a); 0689 } else if(rel>1.) { 0690 D3Equ(&from,b); 0691 } 0692 if(hit_at) 0693 D3Copy(hit_at,&from); 0694 D3SubEqu(&from,pt); 0695 return D3Norm(&from); 0696 } 0697 F64 Friction(CD3 *dxdt,F64 max) { 0698 F64 norm=D3Norm(dxdt); 0699 F64 inp=norm/max,force; 0700 if(inp<1.) 0701 return 1.; 0702 //Sigmoid,cap at around max 0703 F64 sigmoid=1./(1.+Exp(-inp)); 0704 //Weighted average between sigmoid x force fudge 0705 force=max/norm*sigmoid+(1.-sigmoid); 0706 return force; 0707 } 0708 Bool IsProjectile(CGameThing *t) { 0709 return t->ident==PW_ROCKET_IDENT|| 0710 t->ident==PW_GREEN_SHOT_IDENT; 0711 } 0712 U0 Derivative(CMathODE *ode,F64 ,COrder2D3 *,COrder2D3 *) { 0713 LockWorld; 0714 CMass2 *mass,*head=&ode->next_mass,*mass2; 0715 CSpring2 *spr; 0716 F64 d,max,dd,angle,speed; 0717 CD3 tmp,*tmp_ptr,hit_at; 0718 CBurger *burger; 0719 I64 idx=0; 0720 CPinWormBody *body,*body2; 0721 CPinWorm *who; 0722 for(mass=head->next;mass!=head;mass=mass->next) { 0723 if(who=mass->who) { 0724 MemCpy(&who->old_mass,mass,sizeof CMass); 0725 } 0726 if(mass->who&&mass->who->ident==PW_HEAD_IDENT) { 0727 d=Friction(&mass->state->DxDt,who->stats.max_speed*30); 0728 D3MulEqu(&mass->state->DxDt,d); 0729 } else if(mass->who&&mass->who->ident==PW_ROCKET_IDENT) { 0730 d=Friction(&mass->state->DxDt,50*30); 0731 D3MulEqu(&mass->state->DxDt,d); 0732 } else if(mass->who&&mass->who->ident==PW_GREEN_SHOT_IDENT) { 0733 d=Friction(&mass->state->DxDt,300.*30.); 0734 D3MulEqu(&mass->state->DxDt,d); 0735 } else { 0736 D3MulEqu(&mass->state->DxDt,FRICTION); 0737 } 0738 } 0739 for(body=game.objects.next;body!=&game.objects;body=body->qnext) { 0740 tmp_ptr=&body->mass.state->DxDt; 0741 D3AddEqu(tmp_ptr,&body(CPinWorm*)->dx2); 0742 D3Equ(&body(CPinWorm*)->dx2,0,0,0); 0743 if(body->ident==PW_HEAD_IDENT) { 0744 body2=body->next; 0745 D3AddEqu(tmp_ptr,&body(CPinWorm*)->dx); 0746 while(body2) { 0747 spr=&body2->spring; 0748 if(spr->end2&&spr->end1) 0749 body2->angle=Arg(spr->end1->x-spr->end2->x,spr->end1->y-spr->end2->y); 0750 0751 body2=body2->next; 0752 } 0753 } 0754 } 0755 0756 CRocket *rocket; 0757 0758 //Balls repel each other 0759 for(mass=head->next;mass!=head;mass=mass->next) { 0760 for(mass2=head->next;mass2!=head;mass2=mass2->next) { 0761 if(mass!=mass2) { 0762 d=D3NormSqr(D3Sub(&tmp,&mass->state->x,&mass2->state->x))+1.; 0763 max=Max(mass->mass,mass2->mass); 0764 //If burger and worm,burgers seek worm 0765 if(burger=mass->who) { 0766 if(who=mass2->who) { 0767 if(burger->ident==PW_BURGER_IDENT&&who->ident==PW_HEAD_IDENT) { 0768 if(d<300.*300) { 0769 dd=(300.-Sqrt(d))/600.; 0770 D3MulEqu(&tmp,dd); 0771 D3SubEqu(&mass->state->DxDt,&tmp); 0772 goto gravity_skip; 0773 } 0774 } 0775 } 0776 } 0777 if(d<max*max) { 0778 if(rocket=mass->who) { 0779 //Check for player(?) pinworm's body 0780 who=mass2->who; 0781 while(who&&who->ident==PW_BODY_IDENT) { 0782 who=who(CPinWormBody*)->parent; 0783 } 0784 if(who!=rocket) { 0785 rocket->flags|=THINGF_HIT_THING; 0786 rocket->hit_thing=who; 0787 } 0788 } 0789 d=Sqrt(d); 0790 if(mass2->who&&mass2->who->ident==PW_EXPLODE_IDENT) { 0791 if(who=mass->who) 0792 if(mass2->who(CExplosion*)->from!=who) 0793 DamageThing(who,3.*Rand+3.); 0794 dd=(max-d+10)*10; 0795 } else 0796 dd=(max-d)*.5; 0797 D3MulEqu(&tmp,dd/(d+3)); 0798 D3AddEqu(&mass->state->DxDt,&tmp); 0799 gravity_skip:; 0800 } 0801 } 0802 } 0803 } 0804 //Balls cannot pass lines 0805 CLine *line; 0806 CI64Set *lines; 0807 CD3 a,b; 0808 if(game.level) { 0809 for(mass=head->next;mass!=head;mass=mass->next) { 0810 lines=LevelGetLinesInRadius(game.level,mass->state->x,mass->state->y,mass->mass+speed); 0811 0812 for(idx=0;idx!=lines->cnt;++idx) { 0813 line=lines->body[idx]; 0814 a.x=line->start->x; 0815 a.y=line->start->y; 0816 a.z=0; 0817 b.x=line->end->x; 0818 b.y=line->end->y; 0819 b.z=0; 0820 0821 // 0822 // Heres the deal,DONT speed through walls,so check walls within radius of speed 0823 // 0824 tmp.x=mass->state->x+mass->state->DxDt*(1.-1e-15); 0825 tmp.y=mass->state->y+mass->state->DyDt*(1.-1e-15); 0826 tmp.z=0; 0827 if(PlaneIntersect(&hit_at,&mass->state->x,&tmp,&a,&b)) { 0828 D3Sub(&mass->state->DxDt,&hit_at,&mass->state->x); 0829 rocket=mass->who; 0830 if(rocket) 0831 rocket->flags|=THINGF_HIT_LINE; 0832 } 0833 0834 0835 0836 d=LineDist(&a,&b,&mass->state->x,&tmp)+1.; 0837 max=mass->mass/1.5; 0838 if(d<max+5.) { 0839 if(mass->who) { 0840 rocket=mass->who; 0841 rocket->flags|=THINGF_HIT_LINE; 0842 } 0843 D3SubEqu(&tmp,&mass->state->x); 0844 dd=(max*2-d); 0845 D3MulEqu(&tmp,dd/(d+1)); 0846 D3Equ(&mass->state->DxDt,-tmp.x,-tmp.y,0); 0847 } 0848 } 0849 I64SetDel(lines); 0850 next_lines:; 0851 } 0852 } 0853 UnlockWorld; 0854 } 0855 0856 CI64Set *GetThingsOfTypeInRadius(F64 x,F64 y,F64 rad,U64 ident=INVALID_PTR) { 0857 CI64Set *ret=I64SetNew; 0858 //TODO something better 0859 CGameThing *head=&game.objects,*t; 0860 for(t=head->qnext;head!=t;t=t->qnext) { 0861 if(t->ident==ident||ident==INVALID_PTR) 0862 if(Sqr(t->mass.x-x)+Sqr(t->mass.y-y)<rad*rad) 0863 I64SetAdd(ret,t); 0864 } 0865 return ret; 0866 } 0867 U0 CheckPowerUps() { 0868 CBurger *burger,*head=&game.objects; 0869 CPinWorm *pw; 0870 CD3 tmp; 0871 for(burger=head->qnext;burger!=head;burger=burger->qnext) { 0872 for(pw=head->qnext;pw!=head;pw=pw->qnext) { 0873 if(burger->ident==PW_BURGER_IDENT&&pw->ident==PW_HEAD_IDENT) { 0874 if(!(burger->flags&THINGF_TO_DELETE)) { 0875 D3Sub(&tmp,&burger->mass.x,&pw->mass.x); 0876 if(D3Norm(&tmp)<60.&&CanSeeThing(burger,pw)) { 0877 ThingDel(burger,FALSE); //soft delete 0878 PinWormBodyNew(pw); 0879 } 0880 } 0881 } 0882 } 0883 } 0884 } 0885 0886 0887 CPinWorm *PinWormDie(CPinWorm *worm) { 0888 if(worm==player_worm) 0889 player_worm=NULL; 0890 CPinWormBody *body=worm; 0891 CBurger *b; 0892 F64 boom_force,angle; 0893 I64 i; 0894 while(body=body->next) { 0895 b=BurgerNew(body->mass.x,body->mass.y); 0896 angle=Rand*2*pi; 0897 boom_force=Rand*30.+10; 0898 b->dx2=boom_force*Cos(angle); 0899 b->dy2=boom_force*Sin(angle); 0900 0901 //Boom particles 0902 for(i=0;i!=3;++i) 0903 ParticleNew(body->mass.x,body->mass.y,2*pi*Rand,Rand*40.+5.); 0904 0905 ThingDel(body,FALSE); //soft delete 0906 } 0907 b=BurgerNew(worm->mass.x,worm->mass.y); 0908 ThingDel(worm,FALSE); //soft delete 0909 } 0910 0911 U0 ScrnCoordsToWorldCoords(I64 *_x,I64 *_y) { 0912 I64 inv[16],x=*_x,y=*_y,z; 0913 // turn mouse cors to scrn cords 0914 UpdateWorldMatrix; 0915 F64 homogen=world->scrn->r[2*4+3]/ToF64(GR_SCALE); 0916 Mat4x4Equ(inv,world->scrn->r); 0917 Mat4x4Inv(inv); 0918 x=ToF64(*_x-world->scrn->x)/(200./homogen); 0919 y=ToF64(*_y-world->scrn->y)/(200./homogen); 0920 z=1; 0921 Mat4x4MulXYZ(inv,&x,&y,&z); 0922 *_x=x; 0923 *_y=y; 0924 } 0925 U0 PlayerAI(CPinWorm *worm) { 0926 game.camera_center.x=worm->mass.x; 0927 game.camera_center.y=worm->mass.y; 0928 // game.camera_center.z=worm->mass.z; 0929 I64 m,x,y; 0930 I64 wx,wy,sx,sy; 0931 U8 buf[STR_LEN]; 0932 F64 angle=worm->angle,d,dx=worm->dx,dy=worm->dy; 0933 if(!game.game_ui) { 0934 ui_root=game.game_ui=UIRootNew; 0935 worm->health_meter=UIBigTextNew("",40); 0936 worm->food_meter=UIBigTextNew("",40); 0937 worm->hotbar=UIGridNew(10,1); 0938 worm->menu=UITreeNew("Menu"); 0939 worm->menu->no_occupy_space=TRUE; 0940 worm->food_meter->no_occupy_space=TRUE; 0941 worm->health_meter->no_occupy_space=TRUE; 0942 worm->hotbar->no_occupy_space=TRUE; 0943 UIElemAdd(game.game_ui,worm->health_meter); 0944 UIElemAdd(game.game_ui,worm->food_meter); 0945 UIElemAdd(game.game_ui,worm->menu); 0946 UIElemAdd(game.game_ui,worm->hotbar); 0947 0948 } 0949 worm->health_meter->x=mem_task->pix_width-75; 0950 worm->health_meter->y=mem_task->pix_height-75; 0951 worm->health_meter->text=GCStrNew(StrPrint(buf,"Health:\n%fHP",worm->health)); 0952 0953 worm->food_meter->x=75; 0954 worm->food_meter->y=mem_task->pix_height-75; 0955 worm->food_meter->text=GCStrNew(StrPrint(buf,"WormBux:\n$%f",worm->food)); 0956 0957 worm->hotbar->x=Fs->pix_width>>1-worm->hotbar->w2/2.; 0958 worm->hotbar->y=Fs->pix_height-35; 0959 0960 0961 while(m=ScanMsg(&x,&y)) { 0962 if(UIMsg(ui_root,m,x,y)) 0963 goto skip; 0964 if(m==MSG_MS_MOVE) { 0965 ms_x=x; 0966 ms_y=y; 0967 } 0968 if(m==MSG_MS_L_DOWN) { 0969 ms_x=x; 0970 ms_y=y; 0971 } 0972 if(m==MSG_KEY_DOWN) { 0973 if(game.chat_log->focus) { 0974 if(!ChatInteract(game.chat_log,m,x,y)) 0975 goto dft_key; 0976 } else { 0977 dft_key: 0978 if(ToUpper(x)=='T') 0979 game.chat_log->focus=TRUE; 0980 if(x==CH_ESC) { 0981 Exit; 0982 } 0983 } 0984 } 0985 if(m==MSG_MS_L_DOWN||m==MSG_MS_MOVE) { 0986 ms_x=x; 0987 ms_y=y; 0988 sx=x,sy=y; 0989 wx=worm->mass.x; 0990 wy=worm->mass.y; 0991 ScrnCoordsToWorldCoords(&sx,&sy); 0992 worm->look_at_x=sx; 0993 worm->look_at_y=sy; 0994 angle=Arg(dx=sx-wx,dy=sy-wy); 0995 } 0996 0997 if(m==MSG_MS_L_DOWN) { 0998 worm->angle=angle; 0999 // PinWormFireRocket(worm); 1000 // PinWormFireGreen(worm); 1001 PinWormFireBuildWall(worm); 1002 } 1003 skip:; 1004 } 1005 if(worm->health<=0) { 1006 PinWormDie(worm); 1007 return; 1008 } 1009 1010 d=Clamp(Sqrt( 1011 Sqr(dx)+ 1012 Sqr(dy)),15.,worm->stats.max_speed); 1013 worm->dx=dx,worm->dy=dy; 1014 D3Unit(&worm->dx); 1015 D3MulEqu(&worm->dx,d); 1016 if(d>30.) { 1017 worm->angle=angle; 1018 worm->obj->rot=angle; 1019 } 1020 } 1021 #include "AI.HC"; 1022 U0 InitLevelThings() { 1023 CLevel *l=game.level; 1024 CThing *thing,*head=&l->things; 1025 CPinWorm *pw; 1026 for(thing=head->next;thing!=head;thing=thing->next) { 1027 if(!StrCmp(thing->class_name,"Player")) { 1028 pw=PinWormNew(thing->x,thing->y); 1029 pw->ai=&PlayerAI; 1030 pw->health=5000.; 1031 player_worm=pw; 1032 } else if(!StrCmp(thing->class_name,"PinWorm")) { 1033 pw=PinWormNew(thing->x,thing->y); 1034 pw->chat_bot=BotNewFromPersonalityFile("AssHole_Chat.HC"); 1035 QueIns(pw->chat_bot,&game.chat_log->bots); 1036 pw->ai=&AIPinWorm_AI; 1037 } else if(!StrCmp(thing->class_name,"Rocket")) { 1038 RocketNew(thing->x,thing->y); 1039 } else if(!StrCmp(thing->class_name,"Burger")) { 1040 BurgerNew(thing->x,thing->y); 1041 } 1042 } 1043 } 1044 CTask *lock_owner=NULL; 1045 U0 LockWorld() { 1046 if(lock_owner==Fs) 1047 return; 1048 while(LBts(&game.locked_flags,0)) 1049 Yield; 1050 lock_owner=Fs; 1051 } 1052 U0 UnlockWorld() { 1053 lock_owner=NULL; 1054 LBtr(&game.locked_flags,0); 1055 } 1056 U0 PinWormGame() { 1057 game.level=LevelNew; 1058 game.camera_height=0; 1059 game.chat_log=ChatNew; 1060 game.locked_flags=0; 1061 WinBorder; 1062 WinMax; 1063 DocMax; 1064 AutoComplete(0); 1065 Bts(&Fs->win_inhibit,WIf_FOCUS_TASK_MS_L_D); 1066 Bts(&Fs->win_inhibit,WIf_FOCUS_TASK_MS_R_D); 1067 CMathODE *ode=ODENew(0,1e-2,ODEF_HAS_MASSES); 1068 I64 x,y,m,move_x=100,move_y=100,z,inv[16]; 1069 I64 x2,y2,z2; 1070 F64 angle,force,dx,dy; 1071 CMass *to_add; 1072 I64 old_z=ms.pos.z; 1073 world->scrn->flags|=DCF_TRANSFORMATION; 1074 CGameThing *thing,*next; 1075 ode->acceleration_limit=500000.; 1076 ode->derive=&Derivative; 1077 QueIns(ode,Fs->last_ode); 1078 QueInit(&game.objects); 1079 QueInit(&game.particles); 1080 LoadLevel(game.level,"Test.DD"); 1081 LevelInitGrid(game.level); 1082 InitLevelThings; 1083 Fs->draw_it=&PinWormDrawIt; 1084 while(TRUE) { 1085 for(thing=game.objects.next;thing!=&game.objects;thing=next) { 1086 next=thing->qnext; 1087 if(thing->collide_line&&thing->flags&THINGF_HIT_LINE) { 1088 (*thing->collide_line)(thing); 1089 thing->flags&=~THINGF_HIT_LINE; 1090 } 1091 if(thing->collide_thing&&thing->flags&THINGF_HIT_THING) { 1092 (*thing->collide_thing)(thing,thing->hit_thing); 1093 thing->flags&=~THINGF_HIT_THING; 1094 } 1095 if(thing->ai) 1096 (*thing->ai)(thing); 1097 if(thing->animate) 1098 (*thing->animate)(thing); 1099 if(thing->flags&THINGF_EXPLODED) { 1100 force=200.; 1101 if(thing->ident==PW_ROCKET_IDENT) { 1102 force=thing(CRocket*)->explosion_force; 1103 ExplosionNew(thing->mass.x,thing->mass.y,thing(CRocket*)->who_shot_rocket,force); 1104 ThingDel(thing,FALSE); 1105 } 1106 } 1107 } 1108 delete_again:; 1109 for(thing=game.objects.next;thing!=&game.objects;thing=next) { 1110 next=thing->qnext; 1111 if(thing->flags&THINGF_TO_DELETE) { 1112 ThingDel(thing); 1113 goto delete_again; 1114 } 1115 } 1116 UpdateParticles; 1117 CheckPowerUps; 1118 game.camera_height+=(ms.pos.z-old_z)*5.; 1119 if(game.camera_height<0.) { 1120 game.camera_height=0; 1121 } 1122 1123 old_z=ms.pos.z; 1124 LockWorld; 1125 GCCollect; 1126 UnlockWorld; 1127 Refresh; 1128 } 1129 } 1130 //Uf("ExplosionNew"); 1131 PinWormGame; 1132