/** * @brief Player attempts to buy a ship. * @param wid Window player is buying ship from. * @param str Unused. */ static void shipyard_buy( unsigned int wid, char* str ) { (void)str; char *shipname, buf[ECON_CRED_STRLEN]; Ship* ship; shipname = toolkit_getImageArray( wid, "iarShipyard" ); if (strcmp(shipname, "None") == 0) return; ship = ship_get( shipname ); credits_t targetprice = ship_buyPrice(ship); if (land_errDialogue( shipname, "buyShip" )) return; credits2str( buf, targetprice, 2 ); if (dialogue_YesNo("Are you sure?", /* confirm */ "Do you really want to spend %s on a new ship?", buf )==0) return; /* player just got a new ship */ if (player_newShip( ship, NULL, 0, 0 ) == NULL) { /* Player actually aborted naming process. */ return; } player_modCredits( -targetprice ); /* ouch, paying is hard */ /* Update shipyard. */ shipyard_update(wid, NULL); }
/** * @brief Makes sure it's sane to buy a ship, trading the old one in simultaneously. * @param shipname Ship being bought. */ int shipyard_canTrade( char* shipname ) { int failure = 0; Ship* ship; ship = ship_get( shipname ); credits_t price; price = ship_buyPrice( ship ); /* Must have the necessary license, enough credits, and be able to swap ships. */ if (!player_hasLicense(ship->license)) { land_errDialogueBuild( "You lack the %s.", ship->license ); failure = 1; } if (!player_hasCredits( price - player_shipPrice(player.p->name))) { credits_t creditdifference = price - (player_shipPrice(player.p->name) + player.p->credits); char buf[ECON_CRED_STRLEN]; credits2str( buf, creditdifference, 2 ); land_errDialogueBuild( "You need %s more credits.", buf); failure = 1; } if (!can_swap( shipname )) failure = 1; return !failure; }
/** * @brief Creates an escort. * * @param p Parent of the escort (who he's guarding). * @param ship Name of the ship escort should have. * @param pos Position to create escort at. * @param vel Velocity to create escort with. * @param dir Direction to face. * @param type Type of escort. * @param add Whether or not to add it to the escort list. * @return The ID of the escort on success. */ unsigned int escort_create( Pilot *p, char *ship, Vector2d *pos, Vector2d *vel, double dir, EscortType_t type, int add ) { Ship *s; Pilot *pe; unsigned int e; PilotFlags f; unsigned int parent; /* Get important stuff. */ parent = p->id; s = ship_get(ship); /* Set flags. */ pilot_clearFlagsRaw( f ); pilot_setFlagRaw( f, PILOT_NOJUMP ); if (type == ESCORT_TYPE_BAY) pilot_setFlagRaw( f, PILOT_CARRIED ); /* Create the pilot. */ e = pilot_create( s, NULL, p->faction, "escort", dir, pos, vel, f ); pe = pilot_get(e); pe->parent = parent; /* Add to escort list. */ if (add != 0) escort_addList( p, ship, type, e, 1 ); return e; }
/** * @brief Player attempts to buy a ship, trading the current ship in. * @param wid Window player is buying ship from. * @param str Unused. */ static void shipyard_trade( unsigned int wid, char* str ) { (void)str; char *shipname, buf[ECON_CRED_STRLEN], buf2[ECON_CRED_STRLEN], buf3[ECON_CRED_STRLEN], buf4[ECON_CRED_STRLEN]; Ship* ship; shipname = toolkit_getImageArray( wid, "iarShipyard" ); if (strcmp(shipname, "None") == 0) return; ship = ship_get( shipname ); credits_t targetprice = ship_buyPrice(ship); credits_t playerprice = player_shipPrice(player.p->name); if (land_errDialogue( shipname, "tradeShip" )) return; credits2str( buf, targetprice, 2 ); credits2str( buf2, playerprice, 2 ); credits2str( buf3, targetprice - playerprice, 2 ); credits2str( buf4, playerprice - targetprice, 2 ); /* Display the correct dialogue depending on the new ship's price versus the player's. */ if ( targetprice == playerprice ) { if (dialogue_YesNo("Are you sure?", /* confirm */ "Your %s is worth %s, exactly as much as the new ship, so no credits need be exchanged. Are you sure you want to trade your ship in?", player.p->ship->name, buf2)==0) return; } else if ( targetprice < playerprice ) { if (dialogue_YesNo("Are you sure?", /* confirm */ "Your %s is worth %s credits, more than the new ship. For your ship, you will get the new %s and %s credits. Are you sure you want to trade your ship in?", player.p->ship->name, buf2, ship->name, buf4)==0) return; } else if ( targetprice > playerprice ) { if (dialogue_YesNo("Are you sure?", /* confirm */ "Your %s is worth %s, so the new ship will cost %s credits. Are you sure you want to trade your ship in?", player.p->ship->name, buf2, buf3)==0) return; } /* player just got a new ship */ if (player_newShip( ship, NULL, 1, 0 ) == NULL) return; /* Player aborted the naming process. */ player_modCredits( playerprice - targetprice ); /* Modify credits by the difference between ship values. */ land_refuel(); /* The newShip call will trigger a loadGUI that will recreate the land windows. Therefore the land ID will * be void. We must reload in in order to properly update it again.*/ wid = land_getWid(LAND_WINDOW_SHIPYARD); /* Update shipyard. */ shipyard_update(wid, NULL); }
/** * @brief Player attempts to buy a ship, trading the current ship in. * @param wid Window player is buying ship from. * @param str Unused. */ static void shipyard_trade( unsigned int wid, char* str ) { (void)str; char *shipname, buf[ECON_CRED_STRLEN], buf2[ECON_CRED_STRLEN], buf3[ECON_CRED_STRLEN], buf4[ECON_CRED_STRLEN]; Ship* ship; shipname = toolkit_getImageArray( wid, "iarShipyard" ); ship = ship_get( shipname ); credits_t targetprice = ship->price; credits_t playerprice = player_shipPrice(player.p->name); if (land_errDialogue( shipname, "trade" )) return; credits2str( buf, targetprice, 2 ); credits2str( buf2, playerprice, 2 ); credits2str( buf3, targetprice - playerprice, 2 ); credits2str( buf4, playerprice - targetprice, 2 ); /* Display the correct dialogue depending on the new ship's price versus the player's. */ if ( targetprice == playerprice ) { if (dialogue_YesNo("Are you sure?", /* confirm */ "Your %s is worth %s, exactly as much as the new ship, so no credits need be exchanged. Are you sure you want to trade your ship in?", player.p->ship->name, buf2)==0) return; } else if ( targetprice < playerprice ) { if (dialogue_YesNo("Are you sure?", /* confirm */ "Your %s is worth %s credits, more than the new ship. For your ship, you will get the new %s and %s credits. Are you sure you want to trade your ship in?", player.p->ship->name, buf2, ship->name, buf4)==0) return; } else if ( targetprice > playerprice ) { if (dialogue_YesNo("Are you sure?", /* confirm */ "Your %s is worth %s, so the new ship will cost %s credits. Are you sure you want to trade your ship in?", player.p->ship->name, buf2, buf3)==0) return; } /* player just got a new ship */ if (player_newShip( ship, NULL, 1, 0 ) == NULL) return; /* Player aborted the naming process. */ player_modCredits( playerprice - targetprice ); /* Modify credits by the difference between ship values. */ land_checkAddRefuel(); /* Update shipyard. */ shipyard_update(wid, NULL); }
/** * @brief Makes sure it's sane to change ships. * @param shipname Ship being changed to. */ int can_swap( char* shipname ) { int failure = 0; Ship* ship; ship = ship_get( shipname ); if (pilot_cargoUsed(player.p) > ship->cap_cargo) { /* Current ship has too much cargo. */ land_errDialogueBuild( "You have %g tons more cargo than the new ship can hold.", pilot_cargoUsed(player.p) - ship->cap_cargo, ship->name ); failure = 1; } if (pilot_hasDeployed(player.p)) { /* Escorts are in space. */ land_errDialogueBuild( "You can't strand your fighters in space."); failure = 1; } return !failure; }
/** * @brief Makes sure it's sane to buy a ship. * @param shipname Ship being bought. */ int shipyard_canBuy ( char *shipname ) { Ship* ship; ship = ship_get( shipname ); int failure = 0; /* Must have enough credits and the necessary license. */ if (!player_hasLicense(ship->license)) { land_errDialogueBuild( "You lack the %s.", ship->license ); failure = 1; } if (!player_hasCredits( ship->price )) { char buf[ECON_CRED_STRLEN]; credits2str( buf, ship->price - player.p->credits, 2 ); land_errDialogueBuild( "You need %s more credits.", buf); failure = 1; } return !failure; }
/** * @brief Gives the player a new ship. * * @note Should be given when landed, ideally on a planet with a shipyard. * * @usage player.addShip( "Pirate Kestrel", "Seiryuu" ) -- Gives the player a Pirate Kestrel named Seiryuu if player cancels the naming. * * @luaparam ship Name of the ship to add. * @luaparam name Name to give the ship if player refuses to name it. * @luafunc addShip( ship, name ) */ static int playerL_addShip( lua_State *L ) { const char *str, *name; Ship *s; /* Handle parameters. */ str = luaL_checkstring(L, 1); name = luaL_checkstring(L, 2); /* Get ship. */ s = ship_get(str); if (s==NULL) { NLUA_ERROR(L, "Ship '%s' not found.", str); return 0; } /* Add the ship. */ player_newShip( s, 0., 0, 0., 0., 0., name ); return 0; }
/** * @brief Makes sure it's sane to buy a ship. * @param shipname Ship being bought. */ int shipyard_canBuy ( char *shipname, Planet *planet ) { Ship* ship; ship = ship_get( shipname ); int failure = 0; credits_t price; price = ship_buyPrice(ship); /* Must have enough credits and the necessary license. */ if ((!player_hasLicense(ship->license)) && ((planet == NULL) || (!planet_isBlackMarket(planet)))) { land_errDialogueBuild( "You lack the %s.", ship->license ); failure = 1; } if (!player_hasCredits( price )) { char buf[ECON_CRED_STRLEN]; credits2str( buf, price - player.p->credits, 2 ); land_errDialogueBuild( "You need %s more credits.", buf); failure = 1; } return !failure; }
/** * @brief Creates an escort. * * @param parent Parent of the escort (who he's guarding). * @param ship Name of the ship escort should have. * @param pos Position to create escort at. * @param vel Velocity to create escort with. * @param carried Does escort come out of the parent? */ int escort_create( unsigned int parent, char *ship, Vector2d *pos, Vector2d *vel, int carried ) { Ship *s; Pilot *p, *pe; char buf[16]; unsigned int e, f; double dir; /* Get important stuff. */ p = pilot_get(parent); s = ship_get(ship); snprintf(buf, 16, "escort*%u", parent); /* Set flags. */ f = PILOT_ESCORT; if (carried) f |= PILOT_CARRIED; /* Get the direction. */ if (carried) dir = p->solid->dir; else dir = 0.; /* Create the pilot. */ e = pilot_create( s, NULL, p->faction, buf, dir, pos, vel, f ); pe = pilot_get(e); pe->parent = parent; /* Add to escort list. */ p->nescorts++; if (p->nescorts == 1) p->escorts = malloc(sizeof(unsigned int) * ESCORT_PREALLOC); else if (p->nescorts > ESCORT_PREALLOC) p->escorts = realloc( p->escorts, sizeof(unsigned int) * p->nescorts ); p->escorts[p->nescorts-1] = e; return 0; }
/** * @brief Helper function for playerL_addShip. */ static Pilot* playerL_newShip( lua_State *L ) { const char *str, *name, *pntname; Ship *s; Pilot *new_ship; Planet *pnt, *t; int noname; /* Defaults. */ t = NULL; /* Handle parameters. */ str = luaL_checkstring(L, 1); if (lua_gettop(L) > 1) name = luaL_checkstring(L,2); else name = str; if (lua_gettop(L) > 2) pntname = luaL_checkstring (L,3); else pntname = NULL; noname = lua_toboolean(L,4); /* Get planet. */ if (pntname != NULL) { pnt = planet_get( pntname ); if (pnt == NULL) { NLUA_ERROR(L, "Planet '%s' not found!", pntname); return 0; } /* Horrible hack to swap variables. */ t = land_planet; land_planet = pnt; } else pnt = NULL; /* Must be landed if pnt is NULL. */ if ((pnt == NULL) && (land_planet==NULL)) { NLUA_ERROR(L, "Player must be landed to add a ship without location parameter."); return 0; } /* Get ship. */ s = ship_get(str); if (s==NULL) { NLUA_ERROR(L, "Ship '%s' not found.", str); return 0; } /* Add the ship, look in case it's cancelled. */ do { new_ship = player_newShip( s, name, 0, noname ); } while (new_ship == NULL); /* Undo the horrible hack. */ if (t != NULL) land_planet = t; return new_ship; }
/** * @brief Updates the ships in the shipyard window. * @param wid Window to update the ships in. * @param str Unused. */ void shipyard_update( unsigned int wid, char* str ) { (void)str; char *shipname, *license_text; Ship* ship; char buf[PATH_MAX], buf2[ECON_CRED_STRLEN], buf3[ECON_CRED_STRLEN]; size_t len; shipname = toolkit_getImageArray( wid, "iarShipyard" ); /* No ships */ if (strcmp(shipname,"None")==0) { window_modifyImage( wid, "imgTarget", NULL, 0, 0 ); window_disableButton( wid, "btnBuyShip"); window_disableButton( wid, "btnTradeShip"); nsnprintf( buf, PATH_MAX, "None\n" "NA\n" "NA\n" "NA\n" "\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" "\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" ); window_modifyImage( wid, "imgTarget", NULL, 0, 0 ); window_modifyText( wid, "txtStats", NULL ); window_modifyText( wid, "txtDescription", NULL ); window_modifyText( wid, "txtDDesc", buf ); return; } ship = ship_get( shipname ); shipyard_selected = ship; /* update image */ window_modifyImage( wid, "imgTarget", ship->gfx_store, 0, 0 ); /* update text */ window_modifyText( wid, "txtStats", ship->desc_stats ); window_modifyText( wid, "txtDescription", ship->description ); price2str( buf2, ship_buyPrice(ship), player.p->credits, 2 ); credits2str( buf3, player.p->credits, 2 ); /* Remove the word " License". It's redundant and makes the text overflow into another text box */ license_text = ship->license; if (license_text) { len = strlen(ship->license); if (strcmp(" License", ship->license + len - 8) == 0) { license_text = malloc(len - 7); assert(license_text); memcpy(license_text, ship->license, len - 8); license_text[len - 8] = '\0'; } } nsnprintf( buf, PATH_MAX, "%s\n" "%s\n" "%s\n" "%d\n" "\n" "%.0f teraflops\n" "%.0f tons\n" "%.0f kN/ton\n" "%.0f m/s\n" "%.0f deg/s\n" "\n" "%.0f%% damage\n" "%.0f MJ (%.1f MW)\n" "%.0f MJ (%.1f MW)\n" "%.0f MJ (%.1f MW)\n" "%.0f tons\n" "%d units\n" "%.0f units\n" "%s credits\n" "%s credits\n" "%s\n", ship->name, ship_class(ship), ship->fabricator, ship->crew, /* Weapons & Manoeuvrability */ ship->cpu, ship->mass, ship->thrust, ship->speed, ship->turn*180/M_PI, /* Misc */ ship->dmg_absorb*100., ship->shield, ship->shield_regen, ship->armour, ship->armour_regen, ship->energy, ship->energy_regen, ship->cap_cargo, ship->fuel, ship->fuel_consumption, buf2, buf3, (license_text != NULL) ? license_text : "None" ); window_modifyText( wid, "txtDDesc", buf ); if (license_text != ship->license) free(license_text); if (!shipyard_canBuy( shipname, land_planet )) window_disableButtonSoft( wid, "btnBuyShip"); else window_enableButton( wid, "btnBuyShip"); if (!shipyard_canTrade( shipname )) window_disableButtonSoft( wid, "btnTradeShip"); else window_enableButton( wid, "btnTradeShip"); }
/** * @brief Unpersists Lua data. * * @param L State to unperisist data into. * @param parent Node containing all the Lua persisted data. * @return 0 on success. */ static int nxml_unpersistDataNode( lua_State *L, xmlNodePtr parent ) { LuaPlanet p; LuaSystem s; LuaFaction f; LuaShip sh; LuaTime lt; Planet *pnt; StarSystem *ss; xmlNodePtr node; char *name, *type, *buf, *num; int keynum; node = parent->xmlChildrenNode; do { if (xml_isNode(node,"data")) { /* Get general info. */ xmlr_attr(node,"name",name); xmlr_attr(node,"type",type); /* Check to see if key is a number. */ xmlr_attr(node,"keynum",num); if (num != NULL) { keynum = 1; lua_pushnumber(L, atof(name)); free(num); } else lua_pushstring(L, name); /* handle data types */ /* Recursive tables. */ if (strcmp(type,"table")==0) { xmlr_attr(node,"name",buf); /* Create new table. */ lua_newtable(L); /* Save data. */ nxml_unpersistDataNode(L,node); /* Set table. */ free(buf); } else if (strcmp(type,"number")==0) lua_pushnumber(L,xml_getFloat(node)); else if (strcmp(type,"bool")==0) lua_pushboolean(L,xml_getInt(node)); else if (strcmp(type,"string")==0) lua_pushstring(L,xml_get(node)); else if (strcmp(type,"planet")==0) { pnt = planet_get(xml_get(node)); if (pnt != NULL) { p.id = planet_index(pnt); lua_pushplanet(L,p); } else WARN("Failed to load unexistent planet '%s'", xml_get(node)); } else if (strcmp(type,"system")==0) { ss = system_get(xml_get(node)); if (ss != NULL) { s.id = system_index( ss ); lua_pushsystem(L,s); } else WARN("Failed to load unexistent system '%s'", xml_get(node)); } else if (strcmp(type,"faction")==0) { f.f = faction_get(xml_get(node)); lua_pushfaction(L,f); } else if (strcmp(type,"ship")==0) { sh.ship = ship_get(xml_get(node)); lua_pushship(L,sh); } else if (strcmp(type,"time")==0) { lt.t = xml_getLong(node); lua_pushtime(L,lt); } else { WARN("Unknown lua data type!"); lua_pop(L,1); return -1; } /* Set field. */ lua_settable(L, -3); /* cleanup */ free(type); free(name); } } while (xml_nextNode(node)); return 0; }
/** * @brief Parses the fleet node. * * @param temp Fleet to load. * @param parent Parent xml node of the fleet in question. * @return A newly allocated fleet loaded with data in parent node. */ static int fleet_parse( Fleet *temp, const xmlNodePtr parent ) { xmlNodePtr cur, node; FleetPilot* pilot; char* c; int mem; node = parent->xmlChildrenNode; /* Sane defaults and clean up. */ memset( temp, 0, sizeof(Fleet) ); temp->faction = -1; temp->name = (char*)xmlGetProp(parent,(xmlChar*)"name"); /* already mallocs */ if (temp->name == NULL) WARN("Fleet in "FLEET_DATA" has invalid or no name"); do { /* load all the data */ xml_onlyNodes(node); /* Set faction. */ if (xml_isNode(node,"faction")) { temp->faction = faction_get(xml_get(node)); continue; } /* Set AI. */ xmlr_strd(node,"ai",temp->ai); if (ai_getProfile ( temp->ai ) == NULL) WARN("Fleet '%s' has invalid AI '%s'.", temp->name, temp->ai ); /* Set flags. */ if (xml_isNode(node,"flags")){ cur = node->children; do { xml_onlyNodes(cur); WARN("Fleet '%s' has unknown flag node '%s'.", temp->name, cur->name); } while (xml_nextNode(cur)); continue; } /* Load pilots. */ else if (xml_isNode(node,"pilots")) { cur = node->children; mem = 0; do { xml_onlyNodes(cur); if (xml_isNode(cur,"pilot")) { /* See if must grow. */ temp->npilots++; if (temp->npilots > mem) { mem += CHUNK_SIZE; temp->pilots = realloc(temp->pilots, mem * sizeof(FleetPilot)); } pilot = &temp->pilots[temp->npilots-1]; /* Clear memory. */ memset( pilot, 0, sizeof(FleetPilot) ); /* Check for name override */ xmlr_attr(cur,"name",c); pilot->name = c; /* No need to free since it will have to later */ /* Check for AI override */ xmlr_attr(cur,"ai",pilot->ai); /* Load pilot's ship */ xmlr_attr(cur,"ship",c); if (c==NULL) WARN("Pilot %s in Fleet %s has null ship", pilot->name, temp->name); pilot->ship = ship_get(c); if (pilot->ship == NULL) WARN("Pilot %s in Fleet %s has invalid ship", pilot->name, temp->name); if (c!=NULL) free(c); continue; } WARN("Fleet '%s' has unknown pilot node '%s'.", temp->name, cur->name); } while (xml_nextNode(cur)); /* Resize to minimum. */ temp->pilots = realloc(temp->pilots, sizeof(FleetPilot)*temp->npilots); continue; } DEBUG("Unknown node '%s' in fleet '%s'",node->name,temp->name); } while (xml_nextNode(node)); #define MELEMENT(o,s) \ if (o) WARN("Fleet '%s' missing '"s"' element", temp->name) /**< Hack to check for missing fields. */ MELEMENT(temp->ai==NULL,"ai"); MELEMENT(temp->faction==-1,"faction"); MELEMENT(temp->pilots==NULL,"pilots"); #undef MELEMENT return 0; }
/** * @brief Updates the ships in the shipyard window. * @param wid Window to update the ships in. * @param str Unused. */ void shipyard_update( unsigned int wid, char* str ) { (void)str; char *shipname; Ship* ship; char buf[PATH_MAX], buf2[ECON_CRED_STRLEN], buf3[ECON_CRED_STRLEN]; shipname = toolkit_getImageArray( wid, "iarShipyard" ); /* No ships */ if (strcmp(shipname,"None")==0) { window_modifyImage( wid, "imgTarget", NULL, 0, 0 ); window_disableButton( wid, "btnBuyShip"); window_disableButton( wid, "btnTradeShip"); snprintf( buf, PATH_MAX, "None\n" "NA\n" "NA\n" "NA\n" "\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" "\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" "NA\n" ); window_modifyImage( wid, "imgTarget", NULL, 0, 0 ); window_modifyText( wid, "txtStats", NULL ); window_modifyText( wid, "txtDescription", NULL ); window_modifyText( wid, "txtDDesc", buf ); return; } ship = ship_get( shipname ); shipyard_selected = ship; /* update image */ window_modifyImage( wid, "imgTarget", ship->gfx_store, 0, 0 ); /* update text */ window_modifyText( wid, "txtStats", ship->desc_stats ); window_modifyText( wid, "txtDescription", ship->description ); credits2str( buf2, ship->price, 2 ); credits2str( buf3, player.p->credits, 2 ); snprintf( buf, PATH_MAX, "%s\n" "%s\n" "%s\n" "%d\n" "\n" "%.0f teraflops\n" "%.0f tons\n" "%.1f STU average\n" "%.0f kN/ton\n" "%.0f m/s\n" "%.0f deg/s\n" "\n" "%.0f%% damage\n" "%.0f MJ (%.1f MW)\n" "%.0f MJ (%.1f MW)\n" "%.0f MJ (%.1f MW)\n" "%.0f tons\n" "%d units\n" "%s credits\n" "%s credits\n" "%s\n", ship->name, ship_class(ship), ship->fabricator, ship->crew, /* Weapons & Manoeuvrability */ ship->cpu, ship->mass, pow( ship->mass, 1./2.5 ) / 5. * (ship->stats_array.jump_delay/100.+1.), /**< @todo make this more portable. */ ship->thrust / ship->mass, ship->speed, ship->turn*180/M_PI, /* Misc */ ship->dmg_absorb*100., ship->shield, ship->shield_regen, ship->armour, ship->armour_regen, ship->energy, ship->energy_regen, ship->cap_cargo, ship->fuel, buf2, buf3, (ship->license != NULL) ? ship->license : "None" ); window_modifyText( wid, "txtDDesc", buf ); if (!shipyard_canBuy( shipname )) window_disableButton( wid, "btnBuyShip"); else window_enableButton( wid, "btnBuyShip"); if (!shipyard_canTrade( shipname )) window_disableButton( wid, "btnTradeShip"); else window_enableButton( wid, "btnTradeShip"); }