2 * See Licensing and Copyright notice in naev.h
9 * @brief For communicating with planets/pilots.
29 #define BUTTON_WIDTH 80 /**< Button width. */
30 #define BUTTON_HEIGHT 30 /**< Button height. */
32 #define GRAPHIC_WIDTH 256 /**< Width of graphic. */
33 #define GRAPHIC_HEIGHT 256 /**< Height of graphic. */
36 static Pilot
*comm_pilot
= NULL
; /**< Pilot currently talking to. */
37 static Planet
*comm_planet
= NULL
; /**< Planet currently talking to. */
38 static glTexture
*comm_graphic
= NULL
; /**< Pilot's graphic. */
41 /* We need direct pilot access. */
42 extern Pilot
** pilot_stack
;
43 extern int pilot_nstack
;
50 static unsigned int comm_open( glTexture
*gfx
, int faction
,
51 int override
, int bribed
, char *name
);
52 static unsigned int comm_openPilotWindow (void);
53 static void comm_addPilotSpecialButtons( unsigned int wid
);
54 static void comm_close( unsigned int wid
, char *unused
);
55 static void comm_bribePilot( unsigned int wid
, char *unused
);
56 static void comm_bribePlanet( unsigned int wid
, char *unused
);
57 static void comm_requestFuel( unsigned int wid
, char *unused
);
58 static int comm_getNumber( double *val
, char* str
);
59 static const char* comm_getString( char *str
);
63 * @brief Checks to see if comm is open.
65 * @return 1 if comm is open.
67 int comm_isOpen (void)
69 return window_exists( "Communication Channel" );
74 * @brief Opens the communication dialogue with a pilot.
76 * @param pilot Pilot to communicate with.
77 * @return 0 on success.
79 int comm_openPilot( unsigned int pilot
)
88 p
= pilot_get( pilot
);
90 c
= pilot_getFactionColourChar( p
);
92 if (comm_pilot
== NULL
)
95 /* Must not be jumping. */
96 if (pilot_isFlag(comm_pilot
, PILOT_HYPERSPACE
)) {
97 player_message("\e%c%s\er is jumping and can't respond.", c
, comm_pilot
->name
);
101 /* Must not be disabled. */
102 if (pilot_isFlag(comm_pilot
, PILOT_DISABLED
)) {
103 player_message("\e%c%s\er does not respond.", c
, comm_pilot
->name
);
107 /* Check to see if pilot wants to communicate. */
108 msg
= comm_getString( "comm_no" );
110 player_message( msg
);
114 /* Set up for the comm_get* functions. */
115 ai_setPilot( comm_pilot
);
117 /* Have pilot stop hailing. */
118 pilot_rmFlag( comm_pilot
, PILOT_HAILING
);
120 /* Create the pilot window. */
121 wid
= comm_openPilotWindow();
123 /* Run hooks if needed. */
124 run
= pilot_runHook( comm_pilot
, PILOT_HOOK_HAIL
);
126 /* Reopen window in case something changed. */
127 comm_close( wid
, NULL
);
129 comm_openPilotWindow();
137 * @brief Creates the pilot window.
139 static unsigned int comm_openPilotWindow (void)
143 /* Create the generic comm window. */
144 wid
= comm_open( ship_loadCommGFX( comm_pilot
->ship
),
146 pilot_isHostile(comm_pilot
) ? -1 : pilot_isFriendly(comm_pilot
) ? 1 : 0,
147 pilot_isFlag(comm_pilot
, PILOT_BRIBED
),
150 /* Add special buttons. */
151 comm_addPilotSpecialButtons( wid
);
158 * @brief Adds the pilot special buttons to a window.
160 * @param wid Window to add pilot special buttons to.
162 static void comm_addPilotSpecialButtons( unsigned int wid
)
164 window_addButton( wid
, -20, 20 + BUTTON_HEIGHT
+ 20,
165 BUTTON_WIDTH
, BUTTON_HEIGHT
, "btnGreet", "Greet", NULL
);
166 if (!pilot_isFlag(comm_pilot
, PILOT_BRIBED
) && /* Not already bribed. */
167 ((faction_getPlayer( comm_pilot
->faction
) < 0) || /* Hostile. */
168 pilot_isHostile(comm_pilot
)))
169 window_addButton( wid
, -20, 20 + 2*BUTTON_HEIGHT
+ 40,
170 BUTTON_WIDTH
, BUTTON_HEIGHT
, "btnBribe", "Bribe", comm_bribePilot
);
172 window_addButton( wid
, -20, 20 + 2*BUTTON_HEIGHT
+ 40,
173 BUTTON_WIDTH
, BUTTON_HEIGHT
, "btnRequest",
174 "Refuel", comm_requestFuel
);
179 * @brief Opens a communication dialogue with a planet.
181 * @param planet Planet to communicate with.
182 * @return 0 on success.
184 int comm_openPlanet( Planet
*planet
)
188 /* Must not be disabled. */
189 if (!planet_hasService(planet
, PLANET_SERVICE_INHABITED
)) {
190 player_message("%s does not respond.", planet
->name
);
194 comm_planet
= planet
;
196 /* Create the generic comm window. */
197 wid
= comm_open( gl_dupTexture( comm_planet
->gfx_space
),
198 comm_planet
->faction
, 0, 0, comm_planet
->name
);
200 /* Add special buttons. */
201 if (areEnemies(player
->faction
, planet
->faction
) &&
203 window_addButton( wid
, -20, 20 + BUTTON_HEIGHT
+ 20,
204 BUTTON_WIDTH
, BUTTON_HEIGHT
, "btnBribe", "Bribe", comm_bribePlanet
);
211 * @brief Sets up the comm window.
213 * @param gfx Graphic to use for the comm window (is freed).
214 * @param faction Faction of what you're communicating with.
215 * @param override If positive sets to ally, if negative sets to hostile.
216 * @param name Name of object talking to.
217 * @return The comm window id.
219 static unsigned int comm_open( glTexture
*gfx
, int faction
,
220 int override
, int bribed
, char *name
)
229 if (comm_graphic
!= NULL
) {
230 /* First clean up if needed. */
231 gl_freeTexture(comm_graphic
);
235 /* Get faction details. */
237 logo
= faction_logoSmall(faction
);
239 /* Get standing colour / text. */
244 else if (override
< 0) {
248 else if (override
> 0) {
253 stand
= faction_getStandingBroad(faction_getPlayer( faction
));
254 c
= faction_getColour( faction
);
256 w
= MAX(gl_printWidth( NULL
, name
), gl_printWidth( NULL
, stand
));
257 y
= gl_defFont
.h
*2 + 15;
260 y
= MAX( y
, logo
->h
);
262 x
= (GRAPHIC_WIDTH
- w
) / 2;
264 /* Create the window. */
265 wid
= window_create( "Communication Channel", -1, -1,
266 20 + GRAPHIC_WIDTH
+ 20 + BUTTON_WIDTH
+ 20,
267 30 + GRAPHIC_HEIGHT
+ y
+ 5 + 20 );
269 /* Create the ship image. */
270 window_addRect( wid
, 19, -30, GRAPHIC_WIDTH
+1, GRAPHIC_HEIGHT
+ y
+ 5,
271 "rctGFX", &cGrey10
, 1 );
272 window_addImage( wid
, 20 + (GRAPHIC_WIDTH
-(int)comm_graphic
->w
)/2,
273 -30 - (GRAPHIC_HEIGHT
-(int)comm_graphic
->h
)/2,
274 "imgGFX", comm_graphic
, 0 );
278 window_addImage( wid
, x
, -30 - GRAPHIC_HEIGHT
- 5,
279 "imgFaction", logo
, 0 );
281 y
-= (logo
->h
- (gl_defFont
.h
*2 + 15)) / 2;
285 window_addText( wid
, x
, -30 - GRAPHIC_HEIGHT
- y
+ gl_defFont
.h
*2 + 10,
286 GRAPHIC_WIDTH
- x
, 20, 0, "txtName",
287 NULL
, &cDConsole
, name
);
290 window_addText( wid
, x
, -30 - GRAPHIC_HEIGHT
- y
+ gl_defFont
.h
+ 5,
291 GRAPHIC_WIDTH
- x
, 20, 0, "txtStanding", NULL
, c
, stand
);
294 window_addButton( wid
, -20, 20, BUTTON_WIDTH
, BUTTON_HEIGHT
,
295 "btnClose", "Close", comm_close
);
302 * @brief Closes the comm window.
304 * @param wid ID of window calling the function.
305 * @param unused Unused.
307 static void comm_close( unsigned int wid
, char *unused
)
309 /* Clean up a bit after ourselves. */
310 if (comm_graphic
!= NULL
) {
311 gl_freeTexture(comm_graphic
);
316 /* Close the window. */
317 window_close( wid
, unused
);
322 * @brief Tries to bribe the pilot.
324 * @param wid ID of window calling the function.
325 * @param unused Unused.
327 static void comm_bribePilot( unsigned int wid
, char *unused
)
337 str
= comm_getString( "bribe_no" );
339 dialogue_msg("Bribe Pilot", "%s", str
);
343 /* Get amount pilot wants. */
344 if (comm_getNumber( &d
, "bribe" )) {
345 WARN("Pilot '%s' accepts bribes but doesn't give price!", comm_pilot
->name
);
348 price
= (unsigned int) d
;
350 /* Check to see if already bribed. */
352 dialogue_msg("Bribe Pilot", "\"Money won't save your hide now!\"");
357 str
= comm_getString( "bribe_prompt" );
359 answer
= dialogue_YesNo( "Bribe Pilot", "\"I'm gonna need at least %u credits to not leave you as a hunk of floating debris.\"\n\nPay %u credits?", price
, price
);
362 answer
= dialogue_YesNo( "Bribe Pilot", "%s\n\nPay %u credits?", str
, price
);
366 dialogue_msg("Bribe Pilot", "You decide not to pay.");
370 /* Check if has the money. */
371 if (!player_hasCredits( price
)) {
372 dialogue_msg("Bribe Pilot", "You don't have enough credits for the bribery.");
376 player_modCredits( -price
);
377 str
= comm_getString( "bribe_paid" );
379 dialogue_msg("Bribe Pilot", "\"Pleasure to do business with you.\"");
381 dialogue_msg("Bribe Pilot", "%s", str
);
383 /* Mark as bribed and don't allow bribing again. */
384 pilot_setFlag( comm_pilot
, PILOT_BRIBED
);
385 pilot_rmHostile( comm_pilot
);
387 /* Stop hyperspace if necessary. */
388 pilot_rmFlag( comm_pilot
, PILOT_HYP_PREP
);
389 pilot_rmFlag( comm_pilot
, PILOT_HYP_BEGIN
);
391 /* Don't allow rebribe. */
392 L
= comm_pilot
->ai
->L
;
393 lua_getglobal(L
, "mem");
394 lua_pushnumber(L
, 0);
395 lua_setfield(L
, -2, "bribe");
399 window_destroy( wid
);
400 comm_openPilot( comm_pilot
->id
);
405 * @brief Tries to bribe the planet
407 * @param wid ID of window calling the function.
408 * @param unused Unused.
410 static void comm_bribePlanet( unsigned int wid
, char *unused
)
424 standing
= faction_getPlayer( comm_planet
->faction
);
425 /* Get number of hostiles and mass of hostiles. */
428 for (i
=0; i
<pilot_nstack
; i
++) {
429 if (areAllies(comm_planet
->faction
, pilot_stack
[i
]->faction
)) {
431 m
+= pilot_stack
[i
]->solid
->mass
;
434 /* Get now the presence factor - get mass of possible ships and mass */
437 for (i
=0; i
<cur_system
->nfleets
; i
++) {
438 f
= cur_system
->fleets
[i
].fleet
;
439 if (areAllies(comm_planet
->faction
, f
->faction
)) {
442 for (j
=0; j
<f
->npilots
; j
++) {
443 q
+= (double)f
->pilots
[j
].chance
/ 100.;
444 r
+= f
->pilots
[j
].ship
->mass
;
446 q
*= (double)cur_system
->fleets
[i
].chance
/ 100.;
451 /* Calculate the price. */
454 d
= 2000.; /* Base price. */
455 d
*= 0.5 * (o
* (sqrt( p
/ o
) / 9.5)) + /* Base on presence. */
456 0.5 * (n
* (sqrt( m
/ n
) / 9.5)); /* Base on current hostiles. */
457 d
*= 1. + (-1. * standing
) / 50.; /* Modify by standing. */
458 price
= (unsigned int) d
;
461 answer
= dialogue_YesNo( "Bribe Starport",
462 "\"I'll let you land for the small sum of %u credits.\"\n\nPay %u credits?",
467 dialogue_msg("Bribe Starport", "You decide not to pay.");
471 /* Check if has the money. */
472 if (!player_hasCredits( price
)) {
473 dialogue_msg("Bribe Starport", "You don't have enough credits for the bribery.");
478 player_modCredits( -price
);
479 dialogue_msg("Bribe Starport", "You have permission to dock.");
481 /* Mark as bribed and don't allow bribing again. */
482 comm_planet
->bribed
= 1;
485 window_destroy( wid
);
486 comm_openPlanet( comm_planet
);
491 * @brief Tries to request help from the pilot.
493 * @param wid ID of window calling the function.
494 * @param unused Unused.
496 static void comm_requestFuel( unsigned int wid
, char *unused
)
505 /* Check to see if ship has a no refuel message. */
506 msg
= comm_getString( "refuel_no" );
508 dialogue_msg( "Request Fuel", msg
);
512 /* Must need refueling. */
513 if (player
->fuel
>= player
->fuel_max
) {
514 dialogue_msg( "Request Fuel", "Your fuel deposits are already full." );
518 /* See if pilot has enough fuel. */
519 if (comm_pilot
->fuel
< 200.) {
520 dialogue_msg( "Request Fuel",
521 "\"Sorry, I don't have enough fuel to spare at the moment.\"" );
525 /* See if player can get refueled. */
526 ret
= comm_getNumber( &val
, "refuel" );
527 msg
= comm_getString( "refuel_msg" );
528 if ((ret
!= 0) || (msg
== NULL
)) {
529 dialogue_msg( "Request Fuel", "\"Sorry, I'm busy now.\"" );
534 /* Check to see if is already refueling. */
535 if (pilot_isFlag(comm_pilot
, PILOT_REFUELING
)) {
536 dialogue_msg( "Request Fuel", "Pilot is already refueling you." );
540 /* See if player really wants to pay. */
542 ret
= dialogue_YesNo( "Request Fuel", "%s\n\nPay %u credits?", msg
, price
);
544 dialogue_msg( "Request Fuel", "You decide not to pay." );
549 dialogue_msg( "Request Fuel", "%s", msg
);
551 /* Check if he has the money. */
552 if (!player_hasCredits( price
)) {
553 dialogue_msg( "Request Fuel", "You need %u more credits!",
554 price
- player
->credits
);
559 player_modCredits( -price
);
560 pilot_modCredits( comm_pilot
, price
);
562 /* Start refueling. */
563 pilot_rmFlag(comm_pilot
, PILOT_HYP_PREP
| PILOT_HYP_BEGIN
);
564 pilot_setFlag(comm_pilot
, PILOT_REFUELING
);
565 ai_refuel( comm_pilot
, player
->id
);
569 dialogue_msg( "Request Fuel", "\"On my way.\"" );
574 * @brief Gets the amount the communicating pilot wants as a bribe.
576 * Valid targets for now are:
577 * - "bribe": amount pilot wants to be paid.
578 * - "refuel": amount pilot wants to be paid for refueling the player.
580 * @param[out] val Value of the number gotten.
581 * @param str Name of number to get.
582 * @return 0 for success, 1 on error (including not found).
584 static int comm_getNumber( double *val
, char* str
)
589 /* Set up the state. */
590 L
= comm_pilot
->ai
->L
;
591 lua_getglobal( L
, "mem" );
593 /* Get number amount. */
594 lua_getfield( L
, -1, str
);
595 /* Check to see if it's a number. */
596 if (!lua_isnumber(L
, -1))
599 *val
= lua_tonumber(L
, -1);
609 * @brief Gets a string from the pilot's memory.
612 * - comm_no: message of communication failure.
613 * - bribe_no: unbribe message
614 * - bribe_prompt: bribe prompt
615 * - bribe_paid: paid message
617 * @param str String to get.
618 * @return String matching str.
620 static const char* comm_getString( char *str
)
625 /* Get memory table. */
626 L
= comm_pilot
->ai
->L
;
627 lua_getglobal( L
, "mem" );
629 /* Get str message. */
630 lua_getfield(L
, -1, str
);
631 if (!lua_isstring(L
, -1))
634 ret
= lua_tostring(L
, -1);