#include #include #include #include #include #include #include #include "defs.h" #undef hypot #include "struct.h" #include "data.h" #include "packets.h" #include "robot.h" /* These are the flags we get from every player */ #define FLAGMASK (PFSHIELD|PFBOMB|PFORBIT|PFCLOAK|PFROBOT|PFBEAMUP|PFBEAMDOWN|PFPRACTR|PFDOCK|PFTRACT|PFPRESS|PFDOCKOK) #define NO_PFTRACT Player *get_target(); struct planet *closest_planet(); update_players() { register struct player *j, *closest = NULL; register Player *p, *ce = NULL, *cf = NULL, *ct = NULL; register i; int mce = INT_MAX, mcf = INT_MAX, mct = INT_MAX, d; int pldist; int predictx, predicty, rx,ry; Player *nt; if(_state.closest_e && _state.closest_e->p && _state.closest_e->p->p_status == PEXPLODE){ explode_danger = 5/(int)updates + 1; } if(explode_danger) explode_danger --; _state.total_enemies = 0; _state.total_wenemies = 0; _state.closest_e = NULL; _state.total_friends = 0; _state.closest_f = NULL; _state.num_tbombers = 0; _state.num_ttakers = 0; shmem_updmyloc(me->p_x, me->p_y); for(i=0, j= &players[i]; i< MAXPLAYER; i++,j++){ p = &_state.players[j->p_no]; switch(j->p_status){ case PFREE: if(p->last_init){ /* any field not nulled below */ if(j->p_no == _state.controller-1){ _state.controller = 0; locked = 0; } if(_state.last_defend && _state.last_defend->p && _state.last_defend->p->p_no == j->p_no) _state.last_defend = NULL; bzero(p, sizeof(Player)); } continue; case POUTFIT: p->p = NULL; p->dist = GWIDTH; p->p_x = -GWIDTH; p->p_y = -GWIDTH; case PDEAD: case PEXPLODE: if(WAR(j)){ _state.total_enemies ++; } p->alive = 0; p->plcarry = 0.0; if(j->p_team == _state.warteam) _state.total_wenemies ++; continue; } if(j->p_team == _state.warteam) _state.total_wenemies ++; if(j->p_status == PEXPLODE && j->p_explode == 0){ do_expdamage(j); j->p_explode ++; } /* if(j == me) continue; */ if((j!= me) && WAR(j)){ _state.total_enemies ++; p->enemy = 1; } else { _state.total_friends ++; p->enemy = 0; shmem_rloc(j->p_no, &j->p_x, &j->p_y); } if(!p->alive){ /* reset all attributes */ p->p = j; init_sstats(p); } p->alive ++; p->p = j; if(j->p_x < 0 || j->p_y < 0){ /* very little information available */ if ( ! p->invisible ) { p->invisible = 1; /* p->last_init = _udcounter - 1; p->dist = GWIDTH; continue; */ } } else p->invisible = 0; #ifdef NO_PFTRACT /* if server doesn't give tractor info */ /* tractor_check resets or sets this flag */ if(p->pp_flags & PFTRACT){ p->pp_flags = j->p_flags; p->pp_flags |= PFTRACT; } #endif /* NO_PFTRACT */ p->robot = j->p_flags & PFROBOT; if(p->robot) p->fuel = j->p_ship.s_maxfuel; if(j != me){ orbit_check(p, j); army_check1(p, j); army_check2(p, j); if (hm_cr) army_check3(p, j); } if(p->invisible) { p->closest_pl = p->closest_pl; /* keep stale info JKH */ } else { p->closest_pl = closest_planet(j, &pldist, p->closest_pl); p->closest_pl_dist = pldist; } if(j->p_flags & PFBOMB) p->bombing = _udcounter; /* the old information is in p not j */ if(p->invisible) d = GWIDTH; else d = edist_to_me(j); p->lastdist = p->dist; p->dist = d; p->hispr = PHRANGE(p); if(p->invisible){ p->crs = get_wrapcourse(p->p_x, p->p_y); p->icrs = p->crs; /* xxx */ } else{ p->crs = get_wrapcourse(j->p_x, j->p_y); get_intercept_course(p, j, p->dist, &p->icrs); } if(p->enemy && d < mce){ ce = p; mce = d; if(!ignoring_e(p)){ ct = p; mct = d; } } if(p->enemy && d < mct && !ignoring_e(p)){ ct = p; mct = d; } if(!p->enemy && p->p != me && d < mcf){ cf = p; mcf = d; } if(j != me) cloak_check(p, j); if(_udcounter - p->last_init > 450){ /* roughly 45 seconds */ init_sstats(p); } else if(_udcounter - p->last_init == 1){ /* common case for close enemies */ update_sstats(p, 100); } else /* should be actual time in ms, I think */ update_sstats(p, 100 * (_udcounter - p->last_init)); if(p->enemy && !(j->p_flags & PFCLOAK)){ p->thittime = 0; p->phittime = 0; p->thit = p->phit = 0; } if(!p->enemy){ /* what's he doing */ if(_udcounter - p->bombing < 3*60*10) _state.num_tbombers++; } p->last_init = _udcounter; #ifdef nodef if(DEBUG & DEBUG_ENEMY) print_player(p); #endif /* don't update unless it's a value number */ if ( ! p->invisible ) { p->p_x = j->p_x; /* last x */ p->p_y = j->p_y; /* last y */ } } _state.closest_e = ce; _state.closest_f = cf; if(ce) tractor_check(ce, ce->p); nt = get_target(ct); if(nt != _state.current_target){ if(sync_check(&nt)){ _state.current_target = nt; shmem_updmytarg(nt->p->p_no); sendOggVPacket(); } } #ifdef nodef check_server_response(&predictx, &predicty, nint(_serverdelay), NULL, NULL); rx = ABS(me->p_x - predictx); ry = ABS(me->p_y - predicty); /* printf("(sd: %lg) diff: (%d,%d)\n", _serverdelay, rx,ry); */ printf("server (s %d, d %d), local (s %d, d %d), diff (s %d, d %d)\n", _state.sp_subspeed, _state.sp_subdir, _state.p_subspeed, _state.p_subdir, _state.sp_subspeed - _state.p_subspeed, _state.sp_subdir - _state.p_subspeed); #endif /* update my information */ _state.last_x = me->p_x; _state.last_y = me->p_y; _state.last_speed = me->p_speed; _state.last_desspeed = _state.p_desspeed; _state.last_dir = me->p_dir; _state.last_desdir = _state.p_desdir; _state.last_subspeed = _state.p_subspeed; _state.last_subdir = _state.p_subdir; last_udcounter = _udcounter; update_player_density(); check_active_enemies(); } check_active_enemies() { static timer; if(_state.total_enemies == 0){ if(_state.player_type == PT_OGGER || _state.player_type == PT_DOGFIGHTER){ timer ++; if(timer == 100){ mfprintf(stderr, "nobody to fight\n"); exitRobot(0); } } if(_state.timer_delay_ms < 10.0){ mprintf("No enemies: setting 1 update per second\n"); sendUpdatePacket(999999); _state.timer_delay_ms = 10.0; } } else { timer = 0; if(_state.timer_delay_ms > updates){ _state.timer_delay_ms = updates; mprintf("Enemies: setting %d updates per second\n", (int)(1000000./(updates * 100000.))); sendUpdatePacket((int)(updates * 100000.)); } } } orbit_check(p, j) Player *p; struct player *j; { /* begin -- only if PFORBIT not given by server */ #ifdef NO_PFORBIT /* assume nothing has changed. */ if(j->p_speed == 0 && (j->p_flags & PFORBIT)){ if (p->invisible) /* keep old x & y coordinates */ return; p->p_x = j->p_x; p->p_y = j->p_y; return; } j->p_flags &= ~PFORBIT; /* Assume the worst if player is invisible JKH */ if(p->invisible) { if ( p->closest_pl ){ /* grab stale info */ j->p_planet = p->closest_pl->pl_no; } else { j->p_planet = -1; } if(j->p_planet > -1){ j->p_flags |= PFORBIT; p->pl_armies = planets[j->p_planet].pl_armies; if(_state.no_speed_given) j->p_speed = 0; if(DEBUG & DEBUG_ENEMY){ printf("%s invisible orbitting %s\n", j->p_mapchars, planets[j->p_planet].pl_name); } } return; } /* Less info is given about cloaked players too so we need to be pessimistic also JKH */ if (j->p_flags & PFCLOAK) { if ( p->closest_pl && p->closest_pl_dist < 3000 ){ j->p_planet = p->closest_pl->pl_no; } else { j->p_planet = -1; } if(j->p_planet > -1){ j->p_flags |= PFORBIT; p->pl_armies = planets[j->p_planet].pl_armies; if(_state.no_speed_given) j->p_speed = 0; if(DEBUG & DEBUG_ENEMY){ printf("%s Cloaked orbitting %s\n", j->p_mapchars, planets[j->p_planet].pl_name); } } return; } if(j->p_speed == 0 && !_state.no_speed_given){ if(j->p_x != p->p_x || j->p_y != p->p_y){ /* NOTE: could also be tractor */ j->p_planet = planet_from_ppos(j); if(j->p_planet > -1){ j->p_flags |= PFORBIT; p->pl_armies = planets[j->p_planet].pl_armies; if(_state.no_speed_given) j->p_speed = 0; if(DEBUG & DEBUG_ENEMY){ printf("%s orbitting no PFORBIT %s\n", j->p_mapchars, planets[j->p_planet].pl_name); } } } } #endif /* end -- only if PFORBIT not given by server */ if(j->p_flags & PFORBIT){ j->p_planet = planet_from_ppos(j); if(j->p_planet > -1){ if(!p->pl_armies){ p->pl_armies = planets[j->p_planet].pl_armies; } if(_state.no_speed_given) j->p_speed = 0; if(DEBUG & DEBUG_ENEMY){ printf("%s orbiting %s with PFORBIT\n", j->p_mapchars, planets[j->p_planet].pl_name); } } else p->pl_armies = 0; } else p->pl_armies = 0; } army_check1(p, j) Player *p; struct player *j; { struct planet *pl; if(!(j->p_flags & PFBEAMUP) && !(j->p_flags & PFBEAMDOWN)) return; /* don't track robot carriers if told not to JKH */ if ( robdc && !NotRobot(p,j) ) { p->armies=0; p->plcarry=0.0; return; } if(j->p_flags & PFBEAMUP){ if(_udcounter - p->beam_fuse >= 8){ p->armies ++; p->plcarry = 100.; p->beam_fuse = _udcounter; if(DEBUG & DEBUG_ENEMY) printf("%s beamed up 1\n", j->p_mapchars); } } if(j->p_flags & PFBEAMDOWN){ if(_udcounter - p->beam_fuse >= 8){ p->armies --; p->beam_fuse = _udcounter; if(DEBUG & DEBUG_ENEMY) printf("%s beamed down 1\n", j->p_mapchars); } } if((j->p_flags & PFORBIT) && j->p_planet > -1){ pl = &planets[j->p_planet]; if((j->p_swar | j->p_hostile) & pl->pl_owner) if(j->p_flags & PFBEAMDOWN) p->taking = _udcounter; } if(p->armies < 0) p->armies = 0; if(p->armies > troop_capacity(j)) p->armies = troop_capacity(j); } army_check2(p, j) Player *p; struct player *j; { struct planet *pl; bool ohostile = 0, opl = 0; int pa; float ptrate; /* planet taking rate */ static int count=0; if(!(j->p_flags & PFORBIT)) return; /* if(!(j->p_flags & PFBEAMUP) && !(j->p_flags & PFBEAMDOWN)) return; */ if(troop_capacity(j) == 0) return; /* don't track robot carriers if told not to JKH */ if ( robdc && !NotRobot(p,j) ) { p->armies=0; p->plcarry=0.0; return; } pl = &planets[j->p_planet]; if((j->p_swar | j->p_hostile) & pl->pl_owner) ohostile = 1; if(j->p_team == pl->pl_owner) opl = 1; if(!opl && !ohostile) return; if(p->pl_armies == pl->pl_armies) return; /* store old army count in pa */ /* update army count in player based on planet */ pa = p->pl_armies; p->pl_armies = pl->pl_armies; if(pa > pl->pl_armies){ if(ohostile){ if ( pa <= 4) { /* bombing otherwise */ p->armies -= (pa - pl->pl_armies); if(DEBUG & DEBUG_ENEMY) { printf("%s(%s) beaming DOWN %d armies to hostile %s\n", j->p_name, j->p_mapchars, (pa - pl->pl_armies), pl->pl_name); printf("%s(%s) has %d armies.\n", j->p_name, j->p_mapchars, p->armies); } } } else { /* beaming up armies */ /* or someone is bombing under the guy */ p->armies += (pa - pl->pl_armies); if(DEBUG & DEBUG_ENEMY) { printf("%s(%s) beaming UP %d armies from peaceful %s\n", j->p_name, j->p_mapchars, (pa - pl->pl_armies), pl->pl_name); printf("%s(%s) has %d armies.\n", j->p_name, j->p_mapchars, p->armies); } } } else { if(ohostile) return; /* planet is popping */ else{ /* either planet is popping or player is */ /* ferrying armies JKH */ /* as the planet can pop, let's be pessismistic */ /* and just assume it popped */ /* p->armies -= (pl->pl_armies - pa); */ if(DEBUG & DEBUG_ENEMY) { printf("%s(%s) beaming DOWN %d armies to peaceful %s\n", j->p_name, j->p_mapchars, (pl->pl_armies - pa), pl->pl_name); printf("%s(%s) has %d armies.\n", j->p_name, j->p_mapchars, p->armies); } } } if(p->armies < 0) p->armies = 0; if(p->armies > troop_capacity(j)) p->armies = troop_capacity(j); } /* A more intuitive way of figuring out who carries in a pickup game. Only works with humans */ army_check3(p, j) Player *p; struct player *j; { float ptrate; /* planet taking rate */ /* a human alive for long time with enough kills to drop */ /* just assume he carries as he can trick a bot */ if ( j->p_kills == 0 ) /* reset the fuse on death */ p->killfuse = 0; if ( j->p_kills >= 0.51 ) /* increment the fuse tunable JKH */ p->killfuse = p->killfuse + j->p_kills; if ( NotRobot(p,j) ) { if (p->killfuse >= 3000) { /* about 5 min with 1 kill */ p->armies = troop_capacity(j); p->plcarry = 100.0; } } /* > 1.5 kill & high planet rating on player database */ if ( j->p_kills >= 1.5 ) { ptrate = (j->p_stats.st_tplanets * 100000) / j->p_stats.st_tticks; if ( ptrate > 7.0 ) { /* about a planet rating of 4 */ if ( NotRobot(p,j) ) { p->armies = troop_capacity(j); p->plcarry = 100.0; } } } } NotRobot(p, j) Player *p; struct player *j; { if ( (strcmp(j->p_login,"robot!") != 0) || !(j->p_flags&PFBPROBOT) ) { return 1; } else { return 0; } } calc_speed(p, j) Player *p; struct player *j; { double x_speed, y_speed; int s; if(!on_screen(p)) return 0; x_speed = ((double)(j->p_x - p->p_x))/(Cos[j->p_dir] * WARP1); y_speed = ((double)(j->p_y - p->p_y))/(Sin[j->p_dir] * WARP1); if(j->p_x == p->p_x) s = nint(y_speed); else if(j->p_y == p->p_y) s = nint(x_speed); else s = nint(sqrt(x_speed * x_speed + y_speed * y_speed)); /* fixes */ if(s > j->p_speed+1) s /= 2; if(s > j->p_ship.s_maxspeed) s /= 2; /* make sure speed hasn't increased/decreased by more than 1 */ if(s > j->p_speed + 1) s = j->p_speed + 1; else if(s < j->p_speed-1) s = j->p_speed - 1; if(s > j->p_ship.s_maxspeed) s = j->p_ship.s_maxspeed; if(s < 0) s = 0; return s; } cloak_check(p, j) Player *p; struct player *j; { int dist, ns; /* speed & direction is same as when started cloaking unless phaser hit */ if(p->invisible) return; p->pp_flags &= ~PFCLOAK; if((j->p_flags & PFCLOAK) && j->p_cloakphase ++ < CLOAK_PHASES - 1) return; /* not cloaked after phit, for all practical purposes */ if( (j->p_flags & PFCLOAK) && (_udcounter - p->phittime < 12)) p->pp_flags &= ~PFCLOAK; else if(j->p_flags & PFCLOAK) p->pp_flags |= PFCLOAK; if(!(j->p_flags & PFCLOAK) || !(p->pp_flags & PFCLOAK)) return; if(shmem && (ABS(mtime(0) - j->p_lcloakupd) < 100)){ if(shmem_cloakd(j)){ p->pp_flags &= ~PFCLOAK; return; } } if((j->p_flags & PFORBIT) || (j->p_flags & PFBOMB)){ j->p_speed = 0; /* force fire all over planet */ j->p_dir = (unsigned char) (RANDOM() % 256); return; } #ifdef nodef if(p->p_x == j->p_x && p->p_y == j->p_y) /* not updated */ return; #endif if(_state.human){ /* randomize locations a little more */ if(_state.human < 11){ j->p_x = j->p_x + rrnd(_state.human * 1500); j->p_y = j->p_y + rrnd(_state.human * 1500); } else { p->invisible = 1; return; } } j->p_x += (double) (j->p_speed * WARP1) * Cos[j->p_dir]; j->p_y += (double) (j->p_speed * WARP1) * Sin[j->p_dir]; j->p_dir = get_awrapcourse(p->p_x, p->p_y, j->p_x, j->p_y); if(_state.wrap_around) dist = wrap_dist(j->p_x, j->p_y, p->p_x, p->p_y); else dist = (int)hypot((double)(j->p_x-p->p_x), (double)(j->p_y-p->p_y)); ns = dist/(10*WARP1) - 5; if(ns > j->p_speed + 1) ns = j->p_speed + 1; else if(ns < j->p_speed - 1) ns = j->p_speed - 1; if(ns > j->p_ship.s_maxspeed) ns = j->p_ship.s_maxspeed; if(ns < 0) ns = 0; j->p_speed = ns; /* printf("speed: %d, direction: %d\n", j->p_speed, j->p_dir); */ } init_sstats(p) Player *p; { register struct player *j = p->p; /* printf("initing %d\n", j?j->p_no:-1); */ p->fuel = j->p_ship.s_maxfuel; p->shield = j->p_ship.s_maxshield; p->damage = 0; p->wpntemp = 0; p->last_init = _udcounter; p->run_t = 0; p->phit = p->thit = 0; p->thittime = p->phittime = 0; p->phit_me = p->phittime_me = 0; p->armies = 0; p->pl_armies = 0; } update_sstats(e, ct) Player *e; int ct; { register struct player *j = e->p; e->fuel -= subfuel(e->p, ct); if(e->fuel < 0) e->fuel = 0; e->fuel += addfuel(e->p, ct); if(e->fuel > j->p_ship.s_maxfuel) e->fuel = j->p_ship.s_maxfuel; if(e->shield < j->p_ship.s_maxshield) repair_shield(j, e, ct); if(e->damage > 0) repair_damage(j, e, ct); /* if player dies after we die */ if(e->damage > (e->p->p_ship.s_maxdamage + 50)){ e->damage = e->subdamage = 0; } e->wpntemp -= SH_COOLRATE(e->p); if(e->wpntemp < 0) e->wpntemp = 0; } addfuel(k, cycletime) struct player *k; int cycletime; { if((k->p_flags & PFORBIT) && fuel_planet(k->p_planet)){ return (cycletime * 8 * SH_RECHARGE(k))/100; } else if(k->p_flags & PFDOCK) /* could eventually deduct sb fuel here also */ return (cycletime * 12 * SH_RECHARGE(k))/100; else return (cycletime * 2 * SH_RECHARGE(k))/100; } /* xx -- put in util.c */ fuel_planet(n) int n; { struct planet *pl = &planets[n]; if(unknownpl(pl)) return 1; /* benefit of the doubt */ return (pl->pl_flags & PLFUEL); } repair_planet(n) int n; { struct planet *pl = &planets[n]; if(unknownpl(pl)) return 1; /* benefit of the doubt */ return (pl->pl_flags & PLREPAIR); } subfuel(k, cycletime) struct player *k; int cycletime; { int dfuel; dfuel = (cycletime * SH_WARPCOST(k) * k->p_speed)/100; if(k->p_flags & PFSHIELD){ switch(k->p_ship.s_type){ case SCOUT: dfuel += (cycletime * 2)/100; break; case STARBASE: dfuel += (cycletime * 6)/100; default: dfuel += (cycletime * 3)/100; } } if(k->p_flags & PFCLOAK) dfuel += (cycletime * SH_CLOAKCOST(k))/100; if(k->p_flags & PFTRACT) dfuel += TRACTCOST; return dfuel; } repair_shield(k,e, cycletime) struct player *k; Player *e; int cycletime; { if(k->p_speed == 0 && !(k->p_flags & PFSHIELD)){ /* assume he's repairing */ e->subshield += (cycletime * SH_REPAIR(k) * 4)/100; if((k->p_flags & PFORBIT) && repair_planet(k->p_planet)){ e->subshield += (cycletime * SH_REPAIR(k) * 4)/100; } if(k->p_flags & PFDOCK) e->subshield += (cycletime * SH_REPAIR(k) * 6)/100; } else e->subshield += (cycletime * SH_REPAIR(k) * 2)/100; if(e->subshield / 1000){ e->shield += e->subshield / 1000; e->subshield %= 1000; } if(e->shield > k->p_ship.s_maxshield){ e->shield = k->p_ship.s_maxshield; e->subshield = 0; } } repair_damage(k, e, cycletime) struct player *k; Player *e; int cycletime; { if(!(k->p_flags & PFSHIELD)){ if(k->p_speed == 0){ /* assume repairing */ e->subdamage += (cycletime * SH_REPAIR(k)*2)/100; if((k->p_flags & PFORBIT) && repair_planet(k->p_planet)) e->subdamage += (cycletime * SH_REPAIR(k)*2)/100; if(k->p_flags & PFDOCK) e->subdamage += (cycletime * SH_REPAIR(k)*3)/100; } else e->subdamage += (cycletime * SH_REPAIR(k))/100; if(e->subdamage / 1000) { e->damage -= e->subdamage / 1000; e->subdamage %= 1000; } if(e->damage < 0){ e->damage = 0; e->subdamage = 0; } } } /* called from init_dodge */ add_damage(t, td, e) struct torp *t; int td; Player *e; { int ddist; int dx,dy; struct player *j; int dam = 0; j = e->p; if(e->enemy && (j->p_flags & PFCLOAK)){ /* can't guarantee damage but close on location */ if(_udcounter - e->phittime > 10 && !edge_expl(t)){ /* this is more uptodate */ e->thit = 1; e->thittime = _udcounter; e->cx = t->t_x; e->cy = t->t_y; } } dx = t->t_x - j->p_x; dy = t->t_y - j->p_y; if(ABS(dx) > DAMDIST || ABS(dy) > DAMDIST) return; ddist = dx*dx + dy*dy; if(ddist > DAMDIST * DAMDIST) return; if(ddist > EXPDIST * EXPDIST){ dam = td * (DAMDIST - sqrt((double) ddist)) / (DAMDIST - EXPDIST); } else dam = td; if(j == me && dam > 0) hit_by_torp = 1; if(DEBUG & DEBUG_ENEMY) printf("torp dam to %s(%d): %d\n", j->p_name, j->p_no, dam); dodamage(e, j, dam); } dodamage(e, j, dam) Player *e; struct player *j; int dam; { /* if(e->p->p_ship.s_type == STARBASE){ printf("dam before: %d, shields before: %d, dam: %d, max dam: %d\n", e->damage, e->shield, dam, j->p_ship.s_maxdamage); } */ if(dam > 0){ if(j->p_flags & PFSHIELD){ e->shield -= dam; if(e->shield < 0){ e->damage -= e->shield; e->shield = 0; } } else{ e->damage += dam; if(e->damage > j->p_ship.s_maxdamage) e->damage = j->p_ship.s_maxdamage; } } } /* sh just exploded */ do_expdamage(sh) struct player *sh; { register i; int dx,dy,dist; int damage; register struct player *j; register Player *e; for(i=0, e=_state.players; i < MAXPLAYER; i++, e++){ if(!e->p || (e->p->p_status != PALIVE) || (e->invisible)) continue; j = e->p; if (j == sh) continue; dx = sh->p_x - j->p_x; dy = sh->p_y - j->p_y; if (ABS(dx) > SHIPDAMDIST || ABS(dy) > SHIPDAMDIST) continue; dist = dx * dx + dy * dy; if (dist > SHIPDAMDIST * SHIPDAMDIST) continue; if (dist > EXPDIST * EXPDIST) { if (sh->p_ship.s_type == STARBASE) damage = 200 * (SHIPDAMDIST - sqrt((double) dist)) / (SHIPDAMDIST - EXPDIST); else if (sh->p_ship.s_type == SCOUT) damage = 75 * (SHIPDAMDIST - sqrt((double) dist)) / (SHIPDAMDIST - EXPDIST); else damage = 100 * (SHIPDAMDIST - sqrt((double) dist)) / (SHIPDAMDIST - EXPDIST); } else { if (sh->p_ship.s_type == STARBASE) damage = 200; else if (sh->p_ship.s_type == SCOUT) damage = 75; else damage = 100; } if (damage > 0){ dodamage(e, j, damage); if(DEBUG & DEBUG_ENEMY) printf("ship explode dam to %s(%d): %d\n", j->p_name, j->p_no, damage); } } } /* war & peace. Done initially */ /* Times to declare war: 1. When t-mode first starts or when t-mode ended and restarted(done) 2. When you get forced onto another team due to timercide (done) 3. When 3rd space scummer enters game (only happens before t-mode starts So it is covered on step 1.) 4. When 3rd space scummers leave the game. (I have bots declare peace everytime after death, and so this should cover this.) */ int declare_intents(int peaceonly) { register i; register struct player *j; int teams[16], maxt=0, maxcount=0; int maxt2=0, maxcount2=0; int newhostile, pl=0; extern char *team_to_string(); if(me_p->alive < 100 || !isAlive(me)) /* 10 seconds into game */ return 0; if(_state.player_type == PT_OGGER || _state.player_type == PT_DOGFIGHTER) return 0; newhostile = me->p_hostile; bzero(teams, sizeof(teams)); for(i=0, j=players; ip_status == PFREE) continue; if(j->p_flags & PFROBOT) continue; if(me->p_team == j->p_team || j->p_team == 0 || j->p_team == ALLTEAM) continue; teams[j->p_team]++; pl++; } if (!pl) return 0; if(pl){ for(i=1; i< 9; i *= 2) { if(teams[i] > maxcount) { maxt = i; maxcount = teams[i]; } } mprintf("max team = %s\n", team_to_string(maxt)); for(i=1; i< 9; i *= 2) { if( (teams[i] > maxcount2) && (i != maxt) ) { maxt2 = i; maxcount2 = teams[i]; } } mprintf("max team2 = %s\n", team_to_string(maxt2)); } /* peace */ for(i=1; i< 9; i *= 2){ if(i == maxt || i == maxt2) continue; if((i & me->p_hostile) && !(i & me->p_swar)){ /* is hostile to and not at war with */ mprintf("declaring peace with %s\n", team_to_string(i)); newhostile ^= i; } } if (peaceonly) { if(newhostile != me->p_hostile) sendWarReq(newhostile); return 1; } _state.warteam = maxt; /* war */ if(maxt != 0) { if(!((maxt & me->p_swar) && !(maxt & me->p_hostile))) { mprintf("declare war with %s\n", team_to_string(maxt)); newhostile |= maxt; } } /* Being hostile to more teams is better than less teams. */ if(maxt2 != 0) { if(!((maxt2 & me->p_swar) && !(maxt2 & me->p_hostile))) { mprintf("declare war with %s\n", team_to_string(maxt2)); newhostile |= maxt2; } } if(newhostile != me->p_hostile) sendWarReq(newhostile); return 2; } /* DEBUG*/ print_player(e) Player *e; { printf("name: \"%s\"(%d)\n", e->p->p_name, e->p->p_no); printf("%s\n", e->enemy?"enemy":"friend"); printf("last_init %d, (current %d)\n", e->last_init, _udcounter); printf("robot: %s\n", e->robot?"TRUE":"FALSE"); printf("invisible: %s\n", e->invisible?"TRUE":"FALSE"); printf("fuel: %d%%\n", PL_FUEL(e)); printf("shield: %d%%\n", PL_SHIELD(e)); printf("damage: %d%%\n", PL_DAMAGE(e)); } Player *get_target(closest_target) Player *closest_target; { Player *l; Player *getany(), *getabase(); int dummy; if(locked && _state.controller > 0){ l = &_state.players[_state.controller-1]; if(!l || !l->p || !WAR(l->p)){ locked = 0; _state.controller = 0; } else return l; } if(_state.player_type == PT_OGGER) closest_target = getabase(); if(!closest_target) { /* _state.ogg_req = 0; */ return getany(); } if(_state.ogg_req){ if(!_state.current_target){ if(DEBUG & DEBUG_OGG) printf("ogg: no target, resetting\n"); /* _state.ogg_req = 0; */ } else return _state.current_target; } if(_state.protect && closest_target->dist > closest_target->hispr-500){ if(hostilepl(_state.protect_planet)){ unprotectp_c("hostile planet"); if(DEBUG & DEBUG_PROTECT){ printf("hostile planet -- unprotecting.\n"); } return closest_target; } return get_nearest_to_pl(_state.protect_planet); } else if(_state.defend && closest_target->dist > closest_target->hispr-500){ if(!_state.protect_player->p || !isAlive(_state.protect_player->p)){ _state.defend = 0; _state.protect_player = NULL; if(DEBUG & DEBUG_PROTECT){ printf("protect player dead. No longer defending.\n"); } return closest_target; } return get_nearest_to_p(_state.protect_player, &dummy); } else if(!closest_target){ return getany(); } else return closest_target; } process_general_message(message, flags, from, to) char *message; unsigned char flags,from,to; { Player *p; if(from == 255) { /* god */ switch(flags & (MTEAM|MINDIV|MALL)){ case MTEAM: break; case MINDIV: break; default: break; } return; } if(/* from < 0 ||*/ from >= MAXPLAYER){ mfprintf(stderr, "process_general_message: unknown player %d\n", from); return; } p = &_state.players[from]; switch(flags & (MTEAM|MINDIV|MALL)){ case MTEAM: parse_message(&message[10], p, MTEAM); break; case MINDIV: parse_message(&message[10], p, MINDIV); break; default: break; } } tractor_check(e, j) Player *e; struct player *j; { int predictx, predicty, predict_trx, predict_try, edist; register currx, curry, rtx, rty, rx, ry; int trx, try; #ifndef NO_PFTRACT e->pp_flags &= ~PFTRACT; e->pp_flags &= ~PFPRESS; if(j->p_flags & PFTRACT){ e->pp_flags |= PFTRACT; printf("enemy tractor\n"); } if(j->p_flags & PFPRESS) e->pp_flags |= PFPRESS; #else /* if server doesn't give PFTRACT/PFPRESS */ /* printf("cycles: (%g, %d)\n", _serverdelay, nint(_serverdelay)); printf("Last loc (%d,%d), last speed (%d), last dir (%d)\n", _state.last_x, _state.last_y, _state.last_speed, _state.last_dir); printf("Present loc (%d,%d), present speed (%d), present dir (%d)\n", me->p_x, me->p_y, me->p_speed, me->p_dir); printf("Predicted loc (%d,%d)\n", predictx, predicty); printf("%d, %d\n", rx,ry); printf("\n"); */ if((double)e->dist < ((double)TRACTDIST)*SH_TRACTRNG(j)){ int delt = _udcounter - last_udcounter; if(delt <= 0) delt = 1; /* without him tractoring */ check_server_response(&predictx, &predicty, delt, NULL, NULL); /* with him tractoring */ check_server_response(&predict_trx, &predict_try, delt, e, j); /* difference if tractor */ rtx = ABS(me->p_x - predict_trx); rty = ABS(me->p_y - predict_try); /* difference if no tractor -- ideally 0 */ rx = ABS(me->p_x - predictx); ry = ABS(me->p_y - predicty); if(rtx < rx/2 && rty < ry/2){ if(DEBUG & DEBUG_WARFARE){ printf("tractor from %s\n", j->p_name); } /* printf("tractor from %s\n", j->p_name); printf("rtx: %d, rty: %d, rx: %d, ry: %d\n", rtx, rty, rx, ry); */ e->pp_flags |= PFTRACT; } else{ e->pp_flags &= ~PFTRACT; } } else{ e->pp_flags &= ~PFTRACT; } #endif /* NO_PFTRACT */ } update_player_density() { register i,j; register Player *p,*e; register struct player *fr, *en; int st; unsigned char crs; int dist; if(DEBUG & DEBUG_TIME){ st = mtime(0); } for(i=0, p= _state.players; i < MAXPLAYER; i++, p++){ if(!p->p) continue; bzero(p->attacking, sizeof(p->attacking)); if(p->p == me) bzero(_state.attacking_newdir, sizeof(_state.attacking_newdir)); for(j=0; j< MAXPLAYER; j++) p->distances[j] = INT_MAX; } for(i=0, p= _state.players; i < MAXPLAYER; i++, p++){ if(!p->p || !isAlive(p->p)) continue; if(!p->enemy){ fr = p->p; for(j=0, e=_state.players; j < MAXPLAYER; j++,e++) { if(!e->p) continue; if(!e->enemy) continue; en = e->p; /* enemy course to friend */ crs = get_awrapcourse(fr->p_x, fr->p_y, en->p_x, en->p_y); dist = pdist_to_p(fr, en); /* note: independent of distance */ p->distances[j] = dist; /* printf("%s close to %s\n", fr->p_name, en->p_name); printf("ecrs %d, frcrs %d, line %d\n", en->p_dir, fr->p_dir, crs); */ /* this information won't be useful until close however */ if(attacking(e, (unsigned char)(crs-128), 32)) e->attacking[i] = p; if(attacking(p, crs, 32)) p->attacking[j] = e; if(p->p == me){ unsigned char odir = p->p->p_dir; p->p->p_dir = _state.newdir; if(attacking(p, crs, 32)) _state.attacking_newdir[j] = e; p->p->p_dir = odir; } #ifdef nodef /* debug */ if(p->p == me && p->attacking[j] && dist < 6000){ printf("dens: me attack %s (mycrs: %d), (hiscrs: %d)\n", en->p_mapchars, en->p_no, me->p_dir, en->p_dir); } else if(p->p == me && dist < 6000){ printf("dens: NOT attacking %s\n", en->p_mapchars); } #endif } } } calc_attackdiff(); if(DEBUG & DEBUG_TIME){ printf("update_player_density() took %dms\n", mtime(0)-st); } /* DEBUG */ #ifdef nodef for(i=0, p = _state.players; i < MAXPLAYER; i++, p++){ if(!p->p) continue; printf("%s attacking: ", p->p->p_name); for(j=0; j< MAXPLAYER; j++){ if(p->attacking[j]) printf("%s, ", p->attacking[j]->p->p_name); } printf("\n"); } #endif } calc_attackdiff() { register i,j; register Player *p; Player *pe[MAXPLAYER]; int my_pno = me->p_no; int at = 0, df = 0; /* find enemies */ for(i=0, p= _state.players; i < MAXPLAYER; i++, p++){ pe[i] = NULL; if(!p->p || !isAlive(p->p) || !p->enemy) continue; /* int p->distances[] distance from each player Player *p->attacking[] 'p' attacking player. */ if(p->dist < _state.attack_diff_dist){ if(p->attacking[my_pno] && PL_FUEL(p) > 10){ at ++; pe[i] = p; } } } /* check friends */ for(i=0, p= _state.players; i < MAXPLAYER; i++, p++){ if(!p->p || !isAlive(p->p) || p->enemy) continue; if(p->dist < _state.attack_diff_dist && PL_FUEL(p) > 20){ for(j=0; j< MAXPLAYER; j++){ if(pe[j]){ /* attacking one of my enemies */ if(p->attacking[j]){ df ++; break; } } } } } _state.attackers = at; _state.defenders = df; _state.attack_diff = at - df; #ifdef nodef /* tmp */ printf("att %d, def %d\n", at, df); #endif } /* SSS: speed critical */ struct planet *closest_planet(j, dist, opl) struct player *j; int *dist; struct planet *opl; { register k; register struct planet *pl, *rp = opl; register d, mdist = INT_MAX; if(opl && (mdist = ihypot((double)(j->p_x - opl->pl_x), (double)(j->p_y - opl->pl_y))) < 3000){ *dist = mdist; return opl; } for(k=0, pl=planets; k < MAXPLANETS; k++, pl++){ d = ihypot((double)(j->p_x - pl->pl_x), (double)(j->p_y - pl->pl_y)); if(d < mdist){ mdist = d; rp = pl; if(mdist < 3000) break; } } /* printf("%s closest to %s\n", j->p_mapchars, rp?rp->pl_name:"(NULL)"); */ *dist = mdist; return rp; } Player *getany() { register i; register Player *p; struct planet *hp, *team_planet(); for(i=0, p = _state.players; i < MAXPLAYER; i++, p++){ if(!p->p || !isAlive(p->p) || !p->enemy) continue; if(p->invisible){ hp = team_planet(p->p->p_team); if(!hp) continue; p->p->p_x = hp->pl_x; p->p->p_y = hp->pl_y; #ifdef nodef printf("choosing invisible player with hp %s (%d,%d)\n", hp->pl_name, hp->pl_x, hp->pl_y); #endif p->invisible = 0; /* xx */ } return p; } return NULL; } Player *getabase() { register i; register Player *p; struct planet *hp, *team_planet(); int sbs[MAXPLAYER], sbf = 0; for(i=0, p = _state.players; i < MAXPLAYER; i++, p++){ if(!p->p || !isAlive(p->p) || !p->enemy) continue; if(p->p->p_ship.s_type != STARBASE) continue; sbs[sbf++] = i; if(p->invisible){ hp = team_planet(p->p->p_team); if(!hp) continue; p->p->p_x = hp->pl_x; p->p->p_y = hp->pl_y; #ifdef nodef printf("choosing invisible player with hp %s (%d,%d)\n", hp->pl_name, hp->pl_x, hp->pl_y); #endif p->invisible = 0; /* xx */ } } if(!sbf) return NULL; else return &_state.players[ sbs[random()%sbf] ]; } /* make sure edge didn't set off explosion */ edge_expl(t) struct torp *t; { register i = t->t_x, j = t->t_y; return (!i || i == GWIDTH || !j || j == GWIDTH); } sync_check(t) Player **t; { Player *targ = *t; Player *him, *his_targ; int ht; if(!targ || !targ->p) { *t = NULL; return 0; } if(!shmem) return 1; if(!_state.ogg_pno) return 1; check_sync_loop(); ht = shmem_rtarg(_state.ogg_pno-1); if(ht >= 0){ his_targ = &_players[ht]; if(his_targ && his_targ->p){ *t = his_targ; } return 1; } return 1; } check_sync_loop() { struct player *j; char buf[30]; register i = _state.ogg_pno-1, k=0, q; for(k=0; k< MAXPLAYER+1; k++){ q = shmem_rsync(i); /* sprintf(buf, "%d synced with %d", i, q); response(buf); */ i = q; if(q >= 0){ continue; } else return; /* no loop */ } /* otherwise, loop */ fprintf(stderr, "Sync loop detected.\n"); response("sync loop detected"); _state.ogg_pno = 0; shmem_updmysync(-1); }