/** * @brief Returns an array of faction ids. * * @param *n Writes the number of elements. * @param which Which factions to get. (0,1,2,3 : all, friendly, neutral, hostile) * @return A pointer to an array, or NULL. */ int *faction_getGroup( int *n, int which ) { int *group; int i; /* Set defaults. */ group = NULL; *n = 0; switch(which) { case 0: /* 'all' */ *n = faction_nstack; group = malloc(sizeof(int) * *n); for(i = 0; i < faction_nstack; i++) group[i] = i; break; case 1: /* 'friendly' */ for(i = 0; i < faction_nstack; i++) if(areAllies(FACTION_PLAYER, i)) { (*n)++; group = realloc(group, sizeof(int) * *n); group[*n - 1] = i; } break; case 2: /* 'neutral' */ for(i = 0; i < faction_nstack; i++) if(!areAllies(FACTION_PLAYER, i) && !areEnemies(FACTION_PLAYER, i)) { (*n)++; group = realloc(group, sizeof(int) * *n); group[*n - 1] = i; } break; case 3: /* 'hostile' */ for(i = 0; i < faction_nstack; i++) if(areEnemies(FACTION_PLAYER, i)) { (*n)++; group = realloc(group, sizeof(int) * *n); group[*n - 1] = i; } break; default: /* Defaults have already been set. */ break; } return group; }
/** * @brief Performs an appropriate action when a planet is clicked. * * @param planet Index of the planet. * @param autonav Whether to autonav to the target. * @return Whether the click was used. */ int input_clickedPlanet( int planet, int autonav ) { Planet *pnt; pnt = cur_system->planets[ planet ]; if (!planet_isKnown(pnt)) return 0; if (autonav) { player_targetPlanetSet( planet ); player_autonavPnt( pnt->name ); return 1; } if (planet == player.p->nav_planet && input_isDoubleClick((void*)pnt)) { player_hyperspacePreempt(0); if (planet_hasService(pnt, PLANET_SERVICE_LAND)) { if ((pnt->faction >= 0) && (areEnemies( player.p->faction, pnt->faction ) && !pnt->bribed)) player_hailPlanet(); else player_land(); } } else player_targetPlanetSet( planet ); input_clicked( (void*)pnt ); return 1; }
/** * @brief Gets the faction character associated to it's standing with the player. * * Use this to do something like "\e%c", faction_getColourChar( some_faction ) in the * font print routines. * * @param f Faction to get the colour of based on player's standing. * @return The character associated to the faction. */ char faction_getColourChar( int f ) { if (f<0) return 'I'; else if (areEnemies(FACTION_PLAYER,f)) return 'H'; else if (areAllies(FACTION_PLAYER,f)) return 'F'; else return 'N'; }
/** * @brief Gets the colour of the faction based on it's standing with the player. * * Used to unify the colour checks all over. * * @param f Faction to get the colour of based on player's standing. * @return Pointer to the colour. */ const glColour* faction_getColour( int f ) { if (f<0) return &cInert; else if (areAllies(FACTION_PLAYER,f)) return &cFriend; else if (areEnemies(FACTION_PLAYER,f)) return &cHostile; else return &cNeutral; }
/** * @brief Checks to see if f is an enemy of e. * * @usage if f:areEnemies( faction.get( "Dvaered" ) ) then * * @luaparam f Faction to check against. * @luaparam e Faction to check if is an enemy. * @luareturn true if they are enemies, false if they aren't. * @luafunc areEnemies( f, e ) */ static int factionL_areenemies( lua_State *L ) { int f, ff; f = luaL_validfaction(L,1); ff = luaL_validfaction(L,2); lua_pushboolean(L, areEnemies( f, ff )); return 1; }
/** * @brief Calculates the resistance between two star systems. * * @param A Star system to calculate the resistance between. * @param B Star system to calculate the resistance between. * @return Resistance between A and B. */ static double econ_calcJumpR( StarSystem *A, StarSystem *B ) { double R; /* Set to base to ensure price change. */ R = ECON_BASE_RES; /* Modify based on system conditions. */ R += (A->nebu_density + B->nebu_density) / 1000.; /* Density shouldn't affect much. */ R += (A->nebu_volatility + B->nebu_volatility) / 100.; /* Volatility should. */ /* Modify based on global faction. */ if ((A->faction != -1) && (B->faction != -1)) { if (areEnemies(A->faction, B->faction)) R += ECON_FACTION_MOD * ECON_BASE_RES; else if (areAllies(A->faction, B->faction)) R -= ECON_FACTION_MOD * ECON_BASE_RES; } /* @todo Modify based on fleets. */ return R; }
/** * @brief Opens a communication dialogue with a planet. * * @param planet Planet to communicate with. * @return 0 on success. */ int comm_openPlanet( Planet *planet ) { unsigned int wid; /* Must not be disabled. */ if (!planet_hasService(planet, PLANET_SERVICE_BASIC)) { player_message("%s does not respond.", planet->name); return 0; } comm_planet = planet; /* Create the generic comm window. */ wid = comm_open( gl_dupTexture( comm_planet->gfx_space ), comm_planet->faction, 0, 0, comm_planet->name ); /* Add special buttons. */ if (areEnemies(player->faction, planet->faction) && !planet->bribed) window_addButton( wid, -20, 20 + BUTTON_HEIGHT + 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnBribe", "Bribe", comm_bribePlanet ); return 0; }
/** * @brief Handles a click event. */ static void input_clickevent( SDL_Event* event ) { unsigned int pid; Pilot *p; int mx, my, mxr, myr, pntid, jpid; int rx, ry, rh, rw, res; double x, y, m, r, rp, d, dp, px, py; double ang, angp, mouseang; Planet *pnt; JumpPoint *jp; HookParam hparam[2]; /* Generate hook. */ hparam[0].type = HOOK_PARAM_NUMBER; hparam[0].u.num = event->button.button; hparam[1].type = HOOK_PARAM_SENTINAL; hooks_runParam( "mouse", hparam ); /* Handle zoom. */ if (event->button.button == SDL_BUTTON_WHEELUP) { input_clickZoom( 1.1 ); return; } else if (event->button.button == SDL_BUTTON_WHEELDOWN) { input_clickZoom( 0.9 ); return; } /* Middle mouse enables mouse flying. */ if (event->button.button == SDL_BUTTON_MIDDLE) { player_toggleMouseFly(); return; } /* Mouse targetting is left only. */ if (event->button.button != SDL_BUTTON_LEFT) return; /* Player must not be NULL. */ if (player_isFlag(PLAYER_DESTROYED) || (player.p == NULL)) return; px = player.p->solid->pos.x; py = player.p->solid->pos.y; gl_windowToScreenPos( &mx, &my, event->button.x, event->button.y ); gl_screenToGameCoords( &x, &y, (double)mx, (double)my ); if ((mx <= 15 || my <= 15 ) || (my >= gl_screen.h - 15 || mx >= gl_screen.w - 15)) { /* Border */ x = (mx - (gl_screen.w / 2.)) + px; y = (my - (gl_screen.h / 2.)) + py; mouseang = atan2(py - y, px - x); angp = pilot_getNearestAng( player.p, &pid, mouseang, 1 ); ang = system_getClosestAng( cur_system, &pntid, &jpid, x, y, mouseang ); if ((ABS(angle_diff(mouseang, angp)) > M_PI / 64) || ABS(angle_diff(mouseang, ang)) < ABS(angle_diff(mouseang, angp))) pid = PLAYER_ID; /* Pilot angle is too great, or planet/jump is closer. */ if (ABS(angle_diff(mouseang, ang)) > M_PI / 64 ) jpid = pntid = -1; /* Asset angle difference is too great. */ } else { /* Radar targeting requires raw coordinates. */ mxr = event->button.x; myr = gl_screen.rh - event->button.y; gui_radarGetPos( &rx, &ry ); gui_radarGetDim( &rw, &rh ); if ((mxr > rx && mxr <= rx + rw ) && (myr > ry && myr <= ry + rh )) { /* Radar */ m = 1; gui_radarGetRes( &res ); x = (mxr - (rx + rw / 2.)) * res + px; y = (myr - (ry + rh / 2.)) * res + py; } else /* Visual (on-screen) */ m = res = 1. / cam_getZoom(); dp = pilot_getNearestPos( player.p, &pid, x, y, 1 ); d = system_getClosest( cur_system, &pntid, &jpid, x, y ); rp = MAX( 1.5 * PILOT_SIZE_APROX * pilot_get(pid)->ship->gfx_space->sw / 2 * m, 10. * res); if (pntid >=0) { /* Planet is closer. */ pnt = cur_system->planets[ pntid ]; r = MAX( 1.5 * pnt->radius, 100. ); } else if (jpid >= 0) { jp = &cur_system->jumps[ jpid ]; r = MAX( 1.5 * jp->radius, 100. ); } else { r = 0.; } /* Reject pilot if it's too far or a valid asset is closer. */ if (dp > pow2(rp) || (d < pow2(r) && dp < pow2(rp) && dp > d)) pid = PLAYER_ID; if (d > pow2(r)) /* Planet or jump point is too far. */ jpid = pntid = -1; } if (pid != PLAYER_ID) { /* Apply an action if already selected. */ if (!pilot_isFlag(player.p, PILOT_DEAD) && (pid == player.p->target)) { p = pilot_get(pid); if (pilot_isDisabled(p) || pilot_isFlag(p, PILOT_BOARDABLE)) player_board(); else player_hail(); } else player_targetSet( pid ); } else if (pntid >= 0) { /* Planet is closest. */ if (pntid == player.p->nav_planet) { pnt = cur_system->planets[ pntid ]; if (planet_hasService(pnt, PLANET_SERVICE_LAND) && (!areEnemies( player.p->faction, pnt->faction ) || pnt->bribed )) player_land(); else player_hailPlanet(); } else player_targetPlanetSet( pntid ); } else if (jpid >= 0) { /* Jump point is closest. */ jp = &cur_system->jumps[ jpid ]; if (jpid == player.p->nav_hyperspace) { if (space_canHyperspace(player.p)) { if (!paused) player_autonavAbort(NULL); player_jump(); } else player_autonavStart(); } else player_targetHyperspaceSet( jpid ); } }
/** * @brief Renders an individual weapon. * * @param w Weapon to render. * @param dt Current delta tick. */ static void weapon_render( Weapon* w, const double dt ) { double x,y, cx,cy, gx,gy; glTexture *gfx; double z; glColour c = { .r=1., .g=1., .b=1. }; switch (w->outfit->type) { /* Weapons that use sprites. */ case OUTFIT_TYPE_AMMO: case OUTFIT_TYPE_TURRET_AMMO: case OUTFIT_TYPE_BOLT: case OUTFIT_TYPE_TURRET_BOLT: gfx = outfit_gfx(w->outfit); /* Alpha based on strength. */ c.a = w->strength; /* Outfit spins around. */ if (outfit_isProp(w->outfit, OUTFIT_PROP_WEAP_SPIN)) { /* Check timer. */ w->anim -= dt; if (w->anim < 0.) { w->anim = outfit_spin(w->outfit); /* Increment sprite. */ w->sprite++; if (w->sprite >= gfx->sx*gfx->sy) w->sprite = 0; } /* Render. */ if (outfit_isBolt(w->outfit) && w->outfit->u.blt.gfx_end) gl_blitSpriteInterpolate( gfx, w->outfit->u.blt.gfx_end, w->timer / w->life, w->solid->pos.x, w->solid->pos.y, w->sprite % (int)gfx->sx, w->sprite / (int)gfx->sx, &c ); else gl_blitSprite( gfx, w->solid->pos.x, w->solid->pos.y, w->sprite % (int)gfx->sx, w->sprite / (int)gfx->sx, &c ); } /* Outfit faces direction. */ else { if (outfit_isBolt(w->outfit) && w->outfit->u.blt.gfx_end) gl_blitSpriteInterpolate( gfx, w->outfit->u.blt.gfx_end, w->timer / w->life, w->solid->pos.x, w->solid->pos.y, w->sx, w->sy, &c ); else gl_blitSprite( gfx, w->solid->pos.x, w->solid->pos.y, w->sx, w->sy, &c ); } break; /* Beam weapons. */ case OUTFIT_TYPE_BEAM: case OUTFIT_TYPE_TURRET_BEAM: gfx = outfit_gfx(w->outfit); /* Zoom. */ gl_cameraZoomGet( &z ); /* Position. */ gl_cameraGet( &cx, &cy ); gui_getOffset( &gx, &gy ); x = (w->solid->pos.x - cx)*z + gx; y = (w->solid->pos.y - cy)*z + gy; /* Set up the matrix. */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glTranslated( x, y, 0. ); glRotated( 270. + w->solid->dir / M_PI * 180., 0., 0., 1. ); /* Preparatives. */ glEnable(GL_TEXTURE_2D); glBindTexture( GL_TEXTURE_2D, gfx->texture); glShadeModel(GL_SMOOTH); /* Actual rendering. */ glBegin(GL_QUAD_STRIP); /* Start faded. */ ACOLOUR(cWhite, 0.); glTexCoord2d( w->anim, 0. ); glVertex2d( -gfx->sh/2.*z, 0. ); glTexCoord2d( w->anim, 1. ); glVertex2d( +gfx->sh/2.*z, 0. ); /* Full strength. */ COLOUR(cWhite); glTexCoord2d( w->anim + 10. / gfx->sw, 0. ); glVertex2d( -gfx->sh/2.*z, 10.*z ); glTexCoord2d( w->anim + 10. / gfx->sw, 1. ); glVertex2d( +gfx->sh/2.*z, 10.*z ); glTexCoord2d( w->anim + 0.8*w->outfit->u.bem.range / gfx->sw, 0. ); glVertex2d( -gfx->sh/2.*z, 0.8*w->outfit->u.bem.range*z ); glTexCoord2d( w->anim + 0.8*w->outfit->u.bem.range / gfx->sw, 1. ); glVertex2d( +gfx->sh/2.*z, 0.8*w->outfit->u.bem.range*z ); /* Fades out. */ ACOLOUR(cWhite, 0.); glTexCoord2d( w->anim + w->outfit->u.bem.range / gfx->sw, 0. ); glVertex2d( -gfx->sh/2.*z, w->outfit->u.bem.range*z ); glTexCoord2d( w->anim + w->outfit->u.bem.range / gfx->sw, 1. ); glVertex2d( +gfx->sh/2.*z, w->outfit->u.bem.range*z ); glEnd(); /* GL_QUAD_STRIP */ /* Do the beam movement. */ w->anim -= 5. * dt; if (w->anim <= -gfx->sw) w->anim += gfx->sw; /* Clean up. */ glDisable(GL_TEXTURE_2D); glShadeModel(GL_FLAT); glPopMatrix(); /* GL_PROJECTION */ gl_checkErr(); break; default: WARN("Weapon of type '%s' has no render implemented yet!", w->outfit->name); break; } } /** * @brief Checks to see if the weapon can hit the pilot. * * @param w Weapon to check if hits pilot. * @param p Pilot to check if is hit by weapon. * @return 1 if can be hit, 0 if can't. */ static int weapon_checkCanHit( Weapon* w, Pilot *p ) { Pilot *parent; /* Can't hit invincible stuff. */ if (pilot_isFlag(p, PILOT_INVINCIBLE)) return 0; /* Can never hit same faction. */ if (p->faction == w->faction) return 0; /* Go "through" dead pilots. */ if (pilot_isFlag(p, PILOT_DEAD)) return 0; /* Player behaves differently. */ if (w->faction == FACTION_PLAYER) { /* Always hit without safety. */ if (!weapon_safety) return 1; /* Always hit target. */ else if (w->target == p->id) return 1; /* Always hit hostiles. */ else if (pilot_isFlag(p, PILOT_HOSTILE)) return 1; /* Always hit unbribed enemies. */ else if (!pilot_isFlag(p, PILOT_BRIBED) && areEnemies(w->faction, p->faction)) return 1; /* Miss rest - can be neutral/ally. */ else return 0; } /* Let hostiles hit player. */ if (p->faction == FACTION_PLAYER) { parent = pilot_get(w->parent); if (parent != NULL) { if (pilot_isFlag(parent, PILOT_BRIBED)) return 0; if (pilot_isFlag(parent, PILOT_HOSTILE)) return 1; } } /* Hit non-allies. */ if (areEnemies(w->faction, p->faction)) return 1; return 0; }
/** * @brief Applies a hunk and adds it to the diff. * * @param diff Diff to which the hunk belongs. * @param hunk Hunk to apply. * @return 0 on success. */ static int diff_patchHunk( UniHunk_t *hunk ) { Planet *p; int a, b; switch (hunk->type) { /* Adding an asset. */ case HUNK_TYPE_ASSET_ADD: planet_updateLand( planet_get(hunk->u.name) ); return system_addPlanet( system_get(hunk->target.u.name), hunk->u.name ); /* Removing an asset. */ case HUNK_TYPE_ASSET_REMOVE: return system_rmPlanet( system_get(hunk->target.u.name), hunk->u.name ); /* Making an asset a black market. */ case HUNK_TYPE_ASSET_BLACKMARKET: planet_addService( planet_get(hunk->u.name), PLANET_SERVICE_BLACKMARKET ); return 0; /* Making an asset a legal market. */ case HUNK_TYPE_ASSET_LEGALMARKET: planet_rmService( planet_get(hunk->u.name), PLANET_SERVICE_BLACKMARKET ); return 0; /* Adding a Jump. */ case HUNK_TYPE_JUMP_ADD: return system_addJumpDiff( system_get(hunk->target.u.name), hunk->node ); /* Removing a jump. */ case HUNK_TYPE_JUMP_REMOVE: return system_rmJump( system_get(hunk->target.u.name), hunk->u.name ); /* Adding a tech. */ case HUNK_TYPE_TECH_ADD: return tech_addItem( hunk->target.u.name, hunk->u.name ); /* Removing a tech. */ case HUNK_TYPE_TECH_REMOVE: return tech_rmItem( hunk->target.u.name, hunk->u.name ); /* Changing asset faction. */ case HUNK_TYPE_ASSET_FACTION: p = planet_get( hunk->target.u.name ); if (p==NULL) return -1; hunk->o.name = faction_name( p->faction ); return planet_setFaction( p, faction_get(hunk->u.name) ); case HUNK_TYPE_ASSET_FACTION_REMOVE: return planet_setFaction( planet_get(hunk->target.u.name), faction_get(hunk->o.name) ); /* Making a faction visible. */ case HUNK_TYPE_FACTION_VISIBLE: return faction_setInvisible( faction_get(hunk->target.u.name), 0 ); /* Making a faction invisible. */ case HUNK_TYPE_FACTION_INVISIBLE: return faction_setInvisible( faction_get(hunk->target.u.name), 1 ); /* Making two factions allies. */ case HUNK_TYPE_FACTION_ALLY: a = faction_get( hunk->target.u.name ); b = faction_get( hunk->u.name ); if (areAllies(a, b)) hunk->o.data = 'A'; else if (areEnemies(a, b)) hunk->o.data = 'E'; else hunk->o.data = 0; faction_addAlly( a, b ); faction_addAlly( b, a ); return 0; /* Making two factions enemies. */ case HUNK_TYPE_FACTION_ENEMY: a = faction_get( hunk->target.u.name ); b = faction_get( hunk->u.name ); if (areAllies(a, b)) hunk->o.data = 'A'; else if (areEnemies(a, b)) hunk->o.data = 'E'; else hunk->o.data = 0; faction_addEnemy( a, b ); faction_addEnemy( b, a ); return 0; /* Making two factions neutral (removing enemy/ally statuses). */ case HUNK_TYPE_FACTION_NEUTRAL: a = faction_get( hunk->target.u.name ); b = faction_get( hunk->u.name ); if (areAllies(a, b)) hunk->o.data = 'A'; else if (areEnemies(a, b)) hunk->o.data = 'E'; else hunk->o.data = 0; faction_rmAlly( a, b ); faction_rmAlly( b, a ); faction_rmEnemy( a, b ); faction_rmEnemy( b, a ); return 0; /* Resetting the alignment state of two factions. */ case HUNK_TYPE_FACTION_REALIGN: a = faction_get( hunk->target.u.name ); b = faction_get( hunk->u.name ); if (hunk->o.data == 'A') { faction_rmEnemy(a, b); faction_rmEnemy(b, a); faction_addAlly(a, b); faction_addAlly(b, a); } else if (hunk->o.data == 'E') { faction_rmAlly(a, b); faction_rmAlly(b, a); faction_addEnemy(a, b); faction_addAlly(b, a); } else { faction_rmAlly( a, b ); faction_rmAlly( b, a ); faction_rmEnemy( a, b ); faction_rmEnemy( b, a ); } return 0; default: WARN(_("Unknown hunk type '%d'."), hunk->type); break; } return -1; }