/* Here we check to see if the player killed someone who was threatening a carrier-- he was closer than THREAT_DISTANCE away from the carrier. and apparently, there are 10ticks/sec. 14400 distance, which is 8 seconds (80 ticks) at Warp 9. The galaxy is 100k on each side. */ #include #include #include #include #ifdef ESCORT_STAT #define MIN(x,y) (((x)<(y))? (x):(y)) /* the time that deaths are remembered for escort stat purposes, in ticks. */ #define DEATH_SAVE_TIME 90 #define NOMINAL_PLANET_ESCORT_CREDIT 5 /* credit for escorting a successful take */ /* actually, these next two are hard-coded below--don't use the defines */ #define NOMINAL_PLAYER_ESCORT_KCREDIT 3 /* credit for killing a threat to carrier */ #define NOMINAL_PLAYER_ESCORT_DCREDIT 2 /* credit for dying in defense of a carrier */ #define THREAT_DISTANCE 14400 /* this should be the first squared */ #define THREAT_DISTANCE2 2.0736e8 #define THREAT_DISTANCE24 THREAT_DISTANCE2/4.0 /*extern int ticks; a clock? */ /*extern struct status *status; */ void flush_old_deathrecords(int oldness); void empty_deathrecord_list(struct deathrecord *list); /* calculate the distance between two locations. */ float distance(int x1,int y1,int x2,int y2,int flag) { int dx = x1-x2; int dy = y1-y2; if(flag) return sqrt( dx*dx + dy*dy); else return ((float)dx*dx + (float)dy*dy); } struct deathrecord *recent_deaths=0; void record_death(struct player *deader, struct player *killer) { struct deathrecord *newdead = (struct deathrecord *) calloc(1,sizeof(struct deathrecord)); newdead->player = deader->p_no; strcpy(newdead->p_name,deader->p_name); newdead->team = deader->p_team; newdead->x = deader->p_x; newdead->y = deader->p_y; if(killer) newdead->killer = killer->p_no; else newdead->killer=-1; newdead->next = recent_deaths; newdead->dietime = status->time; recent_deaths = newdead; flush_old_deathrecords(DEATH_SAVE_TIME); } /* remove all deathrecords older than oldness ticks. */ void flush_old_deathrecords(int oldness) { struct deathrecord *walk = recent_deaths; if(!walk) return; /* nothing to do */ /* check if the first record needs to be emptied */ if(walk && status->time-walk->dietime > oldness) { free(walk); recent_deaths=0; return; } do { if(walk->next && status->time-walk->next->dietime > oldness) { empty_deathrecord_list(walk->next); walk->next = 0; } walk=walk->next; } while (walk); } /* destroy all the elements of the list */ void empty_deathrecord_list(struct deathrecord *list) { while(list) { struct deathrecord *this=list; list = list->next; free(this); } } /* Have we eliminated a potential threat to one of our carriers? If so, give credit for destroying him. */ int check_escort_kill_credit(struct player *killer, struct player *victim) { /* to do this, we find all the eligible armies, and sum them up. */ int eligible_armies=0; int i; int credit; for(i=0;ip_team) if(distance(killer->p_x,killer->p_y,players[i].p_x,players[i].p_y,0) < THREAT_DISTANCE2) if(players[i].p_ship.s_type!=STARBASE) { /* we don't get credit for self-escorting */ if(&players[i]==killer) continue; eligible_armies+=MIN(6,players[i].p_armies); } } /* 1 credit for 1 army, 1 credit for 2 armies, 2 credits for 3 armies, 2 credits for 4 armies, 3 credits for 5 and 6 armies... */ credit = (int) (eligible_armies/2.0 + 0.6); #ifdef ESCORT_DEBUG if(credit) pmessage(0,MALL,"GOD->ALL", "(escort) Player %d is awarded %d for killing %d, and defending %d armies", killer->p_no, credit, victim->p_no,eligible_armies); #endif killer->p_stats.st_escort+=credit; status->escort+=credit; return 0; } /* did we die nobly, defending a carrier? If we died between a hostile and a carrier, then, yeah.... */ int check_escort_die_credit(struct player *dude,struct player *killer) { int eligible_armies=0; int i; int credit; if(!killer) return 0; for(i=0;ip_team && &players[i]!=dude && players[i].p_armies>0) { int hostile_to_carrierdist; int hostile_to_medist; int me_to_carrierdist; hostile_to_carrierdist = distance(killer->p_x,killer->p_y, players[i].p_x,players[i].p_y,0); /* no credit if this guy killed you far away from the carrier */ if(hostile_to_carrierdist > THREAT_DISTANCE2) continue; me_to_carrierdist = distance(dude->p_x,dude->p_y,players[i].p_x,players[i].p_y,0); /* no credit if I blew up on the carrier!! */ if(me_to_carrierdist < 0.75 * SHIPDAMDIST*SHIPDAMDIST) return 0; hostile_to_medist = distance(dude->p_x,dude->p_y,killer->p_x,killer->p_y,1); /* if we're all sorta in a line, with me sorta in between: we have to take square roots at this point*/ if(sqrt(me_to_carrierdist)+hostile_to_medist < 1.2 * sqrt(hostile_to_carrierdist)) { eligible_armies+=MIN(6,players[i].p_armies); } } } /* less credit than killing him */ /*0,1 armies, 0 credit 2,3,4 armies, 1 credit 5,6 armies, 2 credit */ credit = (int) (eligible_armies/3.0 + 0.6); #ifdef ESCORT_DEBUG if(credit) pmessage(0,MALL,"GOD->ALL", "(escort) Player %d is awarded %d for dying in defense of %d armies", dude->p_no,credit,eligible_armies); #endif dude->p_stats.st_escort+=credit; status->escort+=credit; return 0; } int count_opposition(struct player *taker,int *self_escort_flag) { /* first count the live opposition: live, nonteammembers who are within striking distance*/ struct deathrecord *walk; int opposition=0; int i; *self_escort_flag=0; for(i=0;ip_team && distance(players[i].p_x,players[i].p_y,taker->p_x,taker->p_y,0) < THREAT_DISTANCE2) opposition++; } /* now count the dead opposition: dead enemy players who have died close by recently */ for(walk=recent_deaths;walk;walk=walk->next) { if(walk->team!=taker->p_team && distance(walk->x,walk->y,taker->p_x,taker->p_y,0) < THREAT_DISTANCE2) { if(walk->killer==taker->p_no) *self_escort_flag=1; opposition++; } } return opposition; } int count_and_credit_friends(struct player *taker,int credit) { /* first count the live friends: live, teammembers who are within striking distance*/ struct deathrecord *walk; int friends=0; int i; int self_escort_flag=0; for(i=0;ip_team && distance(players[i].p_x,players[i].p_y,taker->p_x,taker->p_y,0) < THREAT_DISTANCE2) { friends++; if(&players[i]==taker) continue; players[i].p_stats.st_escort+=credit; status->escort+=credit; #ifdef ESCORT_DEBUG if(credit) pmessage(0,MALL,"GOD->ALL", "(escort) Player %d is awarded %d for helping a take.", i,credit) ; #endif } } /* now count the dead friends close by recently */ for(walk=recent_deaths;walk;walk=walk->next) { if(walk->team==taker->p_team && distance(walk->x,walk->y,taker->p_x,taker->p_y,0) < THREAT_DISTANCE2) { friends++; /* no self-escort credit */ players[walk->player].p_stats.st_escort+=credit; status->escort+=credit; #ifdef ESCORT_DEBUG if(credit) pmessage(0,MALL,"GOD->ALL", "(escort) Player %d is awarded %d for helping a take.Too bad he died.", walk->player,credit) ; #endif } } return friends; } /* num_credits is 1 for a destroy, 2 for a take */ int check_escort_planet_take_credit(struct player *taker,int num_credits){ int self_escort; int num_friends; int num_enemies; float credit=NOMINAL_PLANET_ESCORT_CREDIT; /* don't count old opposition/friends */ flush_old_deathrecords(DEATH_SAVE_TIME); num_enemies=count_opposition(taker,&self_escort); num_friends=count_and_credit_friends(taker,0); if(num_friends==0) num_friends=1; /* scale the value: UNOPPOSED takes will give NO escort credit */ credit *= (float)num_enemies/(float)num_friends*num_credits/2.0; /* put a limit on good luck */ credit = MIN(12,credit); #ifdef ESCORT_DEBUG if(credit>0) pmessage(0,MALL,"GOD->ALL", "(escort) Take had %d friends, %d enemies, and was worth %d,%d", num_friends,num_enemies,(int)(credit+0.5),num_credits) ; #endif /* OK, find everyone and give them their credit for escorting a successful take */ count_and_credit_friends(taker,(int)(credit + 0.5)); return 0; } #endif /* ESCORT_STAT */