dab6b51154
git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@64 127b21dd-08f5-0310-b4b7-95ae10353056
7541 lines
220 KiB
Objective-C
7541 lines
220 KiB
Objective-C
//
|
|
// PlayerEntity.m
|
|
/*
|
|
*
|
|
* Oolite
|
|
*
|
|
* Created by Giles Williams on Sat Apr 03 2004.
|
|
* Copyright (c) 2004 for aegidian.org. All rights reserved.
|
|
*
|
|
|
|
Copyright (c) 2004, Giles C Williams
|
|
All rights reserved.
|
|
|
|
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License.
|
|
To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.0/
|
|
or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
|
|
|
|
You are free:
|
|
|
|
• to copy, distribute, display, and perform the work
|
|
• to make derivative works
|
|
|
|
Under the following conditions:
|
|
|
|
• Attribution. You must give the original author credit.
|
|
|
|
• Noncommercial. You may not use this work for commercial purposes.
|
|
|
|
• Share Alike. If you alter, transform, or build upon this work,
|
|
you may distribute the resulting work only under a license identical to this one.
|
|
|
|
For any reuse or distribution, you must make clear to others the license terms of this work.
|
|
|
|
Any of these conditions can be waived if you get permission from the copyright holder.
|
|
|
|
Your fair use and other rights are in no way affected by the above.
|
|
|
|
*/
|
|
|
|
#import "PlayerEntity.h"
|
|
#import "PlayerEntity Additions.h"
|
|
#import "PlayerEntity (contracts).h"
|
|
#import "entities.h"
|
|
|
|
#import "vector.h"
|
|
#import "GameController.h"
|
|
#import "ResourceManager.h"
|
|
#import "Universe.h"
|
|
#import "AI.h"
|
|
#import "MyOpenGLView.h"
|
|
|
|
@implementation PlayerEntity
|
|
|
|
- (void) init_keys
|
|
{
|
|
NSDictionary *kdic = [ResourceManager dictionaryFromFilesNamed:@"keyconfig.plist" inFolder:@"Config" andMerge:YES];
|
|
//
|
|
key_roll_left = gvArrowKeyLeft;
|
|
key_roll_right = gvArrowKeyRight;
|
|
key_pitch_forward = gvArrowKeyUp;
|
|
key_pitch_back = gvArrowKeyDown;
|
|
key_increase_speed = 119; // 'w'
|
|
key_inject_fuel = 105; // 'i'
|
|
key_decrease_speed = 115; // 's'
|
|
key_fire_lasers = 97; // 'a'
|
|
key_target_missile = 116; // 't'
|
|
key_untarget_missile = 117; // 'u'
|
|
key_launch_missile = 109; // 'm'
|
|
key_ecm = 101; // 'e'
|
|
key_launch_escapepod = 27; // 'esc'
|
|
key_energy_bomb = 9; // 'tab'
|
|
key_galactic_hyperspace = 103; // 'g'
|
|
key_hyperspace = 104; // 'h'
|
|
key_jumpdrive = 106; // 'j'
|
|
key_dump_cargo = 100; // 'd'
|
|
key_autopilot = 99; // 'c'
|
|
//
|
|
key_autopilot_target = 67; // 'C'
|
|
//
|
|
key_autodock = 68; // 'D'
|
|
key_snapshot = 42; // '*'
|
|
key_docking_music = 115; // 's'
|
|
key_scanner_zoom = 122; // 'z'
|
|
//
|
|
key_map_dump = 33; // '!'
|
|
key_map_home = gvHomeKey; // 'home'
|
|
//
|
|
key_pausebutton = 112; // 'p'
|
|
key_show_fps = 70; // 'F'
|
|
key_mouse_control = 77; // 'M'
|
|
//
|
|
key_emergency_hyperdrive = 72; // 'H'
|
|
//
|
|
key_next_missile = 121; // 'y'
|
|
key_ident_system = 114; // 'r'
|
|
//
|
|
key_comms_log = 96; // '`'
|
|
//
|
|
key_next_compass_mode = 92; // '\'
|
|
//
|
|
key_cloaking_device = 48; // '0'
|
|
//
|
|
// now check the keyconfig dictionary...
|
|
if ([kdic objectForKey:@"key_roll_left"]) key_roll_left = [(NSNumber *)[kdic objectForKey:@"key_roll_left"] intValue];
|
|
if ([kdic objectForKey:@"key_roll_right"]) key_roll_right = [(NSNumber *)[kdic objectForKey:@"key_roll_right"] intValue];
|
|
if ([kdic objectForKey:@"key_pitch_forward"]) key_pitch_forward = [(NSNumber *)[kdic objectForKey:@"key_pitch_forward"] intValue];
|
|
if ([kdic objectForKey:@"key_pitch_back"]) key_pitch_back = [(NSNumber *)[kdic objectForKey:@"key_pitch_back"] intValue];
|
|
if ([kdic objectForKey:@"key_increase_speed"]) key_increase_speed = [(NSNumber *)[kdic objectForKey:@"key_increase_speed"] intValue];
|
|
if ([kdic objectForKey:@"key_decrease_speed"]) key_decrease_speed = [(NSNumber *)[kdic objectForKey:@"key_decrease_speed"] intValue];
|
|
if ([kdic objectForKey:@"key_inject_fuel"]) key_inject_fuel = [(NSNumber *)[kdic objectForKey:@"key_inject_fuel"] intValue];
|
|
if ([kdic objectForKey:@"key_fire_lasers"]) key_fire_lasers = [(NSNumber *)[kdic objectForKey:@"key_fire_lasers"] intValue];
|
|
if ([kdic objectForKey:@"key_target_missile"]) key_target_missile = [(NSNumber *)[kdic objectForKey:@"key_target_missile"] intValue];
|
|
if ([kdic objectForKey:@"key_untarget_missile"]) key_untarget_missile = [(NSNumber *)[kdic objectForKey:@"key_untarget_missile"] intValue];
|
|
if ([kdic objectForKey:@"key_launch_missile"]) key_launch_missile = [(NSNumber *)[kdic objectForKey:@"key_launch_missile"] intValue];
|
|
if ([kdic objectForKey:@"key_ecm"]) key_ecm = [(NSNumber *)[kdic objectForKey:@"key_ecm"] intValue];
|
|
if ([kdic objectForKey:@"key_launch_escapepod"]) key_launch_escapepod = [(NSNumber *)[kdic objectForKey:@"key_launch_escapepod"] intValue];
|
|
if ([kdic objectForKey:@"key_energy_bomb"]) key_energy_bomb = [(NSNumber *)[kdic objectForKey:@"key_energy_bomb"] intValue];
|
|
if ([kdic objectForKey:@"key_galactic_hyperspace"]) key_galactic_hyperspace = [(NSNumber *)[kdic objectForKey:@"key_galactic_hyperspace"] intValue];
|
|
if ([kdic objectForKey:@"key_hyperspace"]) key_hyperspace = [(NSNumber *)[kdic objectForKey:@"key_hyperspace"] intValue];
|
|
if ([kdic objectForKey:@"key_jumpdrive"]) key_jumpdrive = [(NSNumber *)[kdic objectForKey:@"key_jumpdrive"] intValue];
|
|
if ([kdic objectForKey:@"key_dump_cargo"]) key_dump_cargo = [(NSNumber *)[kdic objectForKey:@"key_dump_cargo"] intValue];
|
|
if ([kdic objectForKey:@"key_autopilot"]) key_autopilot = [(NSNumber *)[kdic objectForKey:@"key_autopilot"] intValue];
|
|
if ([kdic objectForKey:@"key_autodock"]) key_autodock = [(NSNumber *)[kdic objectForKey:@"key_autodock"] intValue];
|
|
if ([kdic objectForKey:@"key_snapshot"]) key_snapshot = [(NSNumber *)[kdic objectForKey:@"key_snapshot"] intValue];
|
|
if ([kdic objectForKey:@"key_docking_music"]) key_docking_music = [(NSNumber *)[kdic objectForKey:@"key_docking_music"] intValue];
|
|
if ([kdic objectForKey:@"key_scanner_zoom"]) key_scanner_zoom = [(NSNumber *)[kdic objectForKey:@"key_scanner_zoom"] intValue];
|
|
//
|
|
if ([kdic objectForKey:@"key_map_dump"]) key_map_dump = [(NSNumber *)[kdic objectForKey:@"key_map_dump"] intValue];
|
|
if ([kdic objectForKey:@"key_map_home"]) key_map_home = [(NSNumber *)[kdic objectForKey:@"key_map_home"] intValue];
|
|
//
|
|
if ([kdic objectForKey:@"key_emergency_hyperdrive"])
|
|
key_emergency_hyperdrive = [(NSNumber *)[kdic objectForKey:@"key_emergency_hyperdrive"] intValue];
|
|
//
|
|
if ([kdic objectForKey:@"key_next_missile"])
|
|
key_next_missile = [(NSNumber *)[kdic objectForKey:@"key_next_missile"] intValue];
|
|
if ([kdic objectForKey:@"key_ident_system"])
|
|
key_ident_system = [(NSNumber *)[kdic objectForKey:@"key_ident_system"] intValue];
|
|
//
|
|
if ([kdic objectForKey:@"key_comms_log"])
|
|
key_comms_log = [(NSNumber *)[kdic objectForKey:@"key_comms_log"] intValue];
|
|
//
|
|
if ([kdic objectForKey:@"key_next_compass_mode"])
|
|
key_next_compass_mode = [(NSNumber *)[kdic objectForKey:@"key_next_compass_mode"] intValue];
|
|
//
|
|
if ([kdic objectForKey:@"key_cloaking_device"])
|
|
key_cloaking_device = [(NSNumber *)[kdic objectForKey:@"key_cloaking_device"] intValue];
|
|
//
|
|
// other keys are SET and cannot be varied
|
|
}
|
|
|
|
- (void) unloadCargoPods
|
|
{
|
|
/* loads commodities from the cargo pods onto the ship's manifest */
|
|
int i;
|
|
NSMutableArray* localMarket = [docked_station localMarket];
|
|
NSMutableArray* manifest = [[NSMutableArray arrayWithArray:localMarket] retain]; // retain
|
|
//
|
|
// zero the quantities in the manifest, making a mutable array of mutable arrays
|
|
//
|
|
for (i = 0; i < [manifest count]; i++)
|
|
{
|
|
NSMutableArray* commodityInfo = [NSMutableArray arrayWithArray:(NSArray *)[manifest objectAtIndex:i]];
|
|
[commodityInfo replaceObjectAtIndex:MARKET_QUANTITY withObject:[NSNumber numberWithInt:0]];
|
|
[manifest replaceObjectAtIndex:i withObject:commodityInfo];
|
|
}
|
|
//
|
|
NSArray* cargoArray = [[NSArray arrayWithArray:cargo] retain]; // retain
|
|
//
|
|
// step through the cargo pods adding in the quantities
|
|
//
|
|
for (i = 0; i < [cargoArray count]; i++)
|
|
{
|
|
NSMutableArray* commodityInfo;
|
|
int co_type, co_amount, quantity;
|
|
|
|
co_type = [(ShipEntity *)[cargoArray objectAtIndex:i] getCommodityType];
|
|
co_amount = [(ShipEntity *)[cargoArray objectAtIndex:i] getCommodityAmount];
|
|
|
|
//NSLog(@"unloading a %@ with %@", [(ShipEntity *)[cargoArray objectAtIndex:i] name], [universe describeCommodity:co_type amount:co_amount]);
|
|
|
|
commodityInfo = (NSMutableArray *)[manifest objectAtIndex:co_type];
|
|
quantity = [(NSNumber *)[commodityInfo objectAtIndex:MARKET_QUANTITY] intValue] + co_amount;
|
|
|
|
[commodityInfo replaceObjectAtIndex:MARKET_QUANTITY withObject:[NSNumber numberWithInt:quantity]]; // enter the adjusted quantity
|
|
}
|
|
[shipCommodityData release];
|
|
shipCommodityData = [[NSArray arrayWithArray:manifest] retain];
|
|
[manifest release]; // release, done
|
|
[cargoArray release]; // release, done
|
|
for (i = 0; i < [cargoArray count]; i++) // recycle these entities rather than leave them to be garbage collected
|
|
{
|
|
[(Entity *)[cargoArray objectAtIndex:i] setStatus:STATUS_DEAD];
|
|
[universe recycleOrDiscard:(Entity *)[cargoArray objectAtIndex:i]];
|
|
}
|
|
[cargo removeAllObjects]; // empty the hold
|
|
}
|
|
|
|
- (void) loadCargoPods
|
|
{
|
|
/* loads commodities from the ships manifest into individual cargo pods */
|
|
int i,j;
|
|
NSMutableArray* localMarket = [docked_station localMarket];
|
|
NSMutableArray* manifest = [[NSMutableArray arrayWithArray:shipCommodityData] retain]; // retain
|
|
for (i = 0; i < [manifest count]; i++)
|
|
{
|
|
NSMutableArray* commodityInfo = [[NSMutableArray arrayWithArray:(NSArray *)[manifest objectAtIndex:i]] retain]; // retain
|
|
int quantity = [(NSNumber *)[commodityInfo objectAtIndex:MARKET_QUANTITY] intValue];
|
|
int units = [universe unitsForCommodity:i];
|
|
|
|
if (quantity > 0)
|
|
{
|
|
//NSLog(@"loading containers with %@",[universe describeCommodity:i amount:quantity]);
|
|
|
|
if (units != UNITS_TONS)
|
|
{
|
|
int amount_per_container = (units == UNITS_KILOGRAMS)? 1000 : 1000000;
|
|
while (quantity > 0)
|
|
{
|
|
int smaller_quantity = 1 + ((quantity - 1) % amount_per_container);
|
|
ShipEntity* container = [universe getShipWithRole:@"cargopod"];
|
|
[container setUniverse:universe];
|
|
[container setScanClass: CLASS_CARGO];
|
|
[container setCommodity:i andAmount:smaller_quantity];
|
|
[cargo addObject:container];
|
|
[container release];
|
|
quantity -= smaller_quantity;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// put each ton in a separate container
|
|
for (j = 0; j < quantity; j++)
|
|
{
|
|
ShipEntity* container = [universe getShipWithRole:@"cargopod"];
|
|
[container setUniverse:universe];
|
|
[container setScanClass: CLASS_CARGO];
|
|
[container setStatus:STATUS_IN_HOLD];
|
|
[container setCommodity:i andAmount:1];
|
|
[cargo addObject:container];
|
|
[container release];
|
|
}
|
|
}
|
|
[commodityInfo setArray:(NSArray *)[localMarket objectAtIndex:i]];
|
|
[commodityInfo replaceObjectAtIndex:MARKET_QUANTITY withObject:[NSNumber numberWithInt:0]];
|
|
[manifest replaceObjectAtIndex:i withObject:[NSArray arrayWithArray:commodityInfo]];
|
|
}
|
|
[commodityInfo release]; // release, done
|
|
}
|
|
[shipCommodityData release];
|
|
shipCommodityData = [[NSArray arrayWithArray:manifest] retain];
|
|
[manifest release]; // release, done
|
|
}
|
|
|
|
- (int) random_factor
|
|
{
|
|
return market_rnd;
|
|
}
|
|
|
|
- (Random_Seed) galaxy_seed
|
|
{
|
|
return galaxy_seed;
|
|
}
|
|
|
|
- (NSPoint) galaxy_coordinates
|
|
{
|
|
return galaxy_coordinates;
|
|
}
|
|
|
|
- (NSPoint) cursor_coordinates
|
|
{
|
|
return cursor_coordinates;
|
|
}
|
|
|
|
- (Random_Seed) system_seed
|
|
{
|
|
return system_seed;
|
|
}
|
|
|
|
- (void) setSystem_seed:(Random_Seed) s_seed
|
|
{
|
|
system_seed = s_seed;
|
|
galaxy_coordinates = NSMakePoint( s_seed.d, s_seed.b);
|
|
}
|
|
|
|
- (Random_Seed) target_system_seed
|
|
{
|
|
return target_system_seed;
|
|
}
|
|
|
|
- (NSDictionary *) commanderDataDictionary
|
|
{
|
|
NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:20]; // retained
|
|
|
|
NSString *gal_seed = [NSString stringWithFormat:@"%d %d %d %d %d %d",galaxy_seed.a, galaxy_seed.b, galaxy_seed.c, galaxy_seed.d, galaxy_seed.e, galaxy_seed.f];
|
|
NSString *gal_coords = [NSString stringWithFormat:@"%d %d",(int)galaxy_coordinates.x,(int)galaxy_coordinates.y];
|
|
|
|
[result setObject:gal_seed forKey:@"galaxy_seed"];
|
|
[result setObject:gal_coords forKey:@"galaxy_coordinates"];
|
|
//
|
|
[result setObject:player_name forKey:@"player_name"];
|
|
//
|
|
[result setObject:[NSNumber numberWithInt:credits] forKey:@"credits"];
|
|
[result setObject:[NSNumber numberWithInt:fuel] forKey:@"fuel"];
|
|
//
|
|
[result setObject:[NSNumber numberWithInt:galaxy_number] forKey:@"galaxy_number"];
|
|
//
|
|
[result setObject:[NSNumber numberWithInt:forward_weapon] forKey:@"forward_weapon"];
|
|
[result setObject:[NSNumber numberWithInt:aft_weapon] forKey:@"aft_weapon"];
|
|
[result setObject:[NSNumber numberWithInt:port_weapon] forKey:@"port_weapon"];
|
|
[result setObject:[NSNumber numberWithInt:starboard_weapon] forKey:@"starboard_weapon"];
|
|
//
|
|
[result setObject:[NSNumber numberWithInt:max_cargo + 5 * max_passengers] forKey:@"max_cargo"];
|
|
//
|
|
[result setObject:shipCommodityData forKey:@"shipCommodityData"];
|
|
//
|
|
[result setObject:[NSNumber numberWithBool:has_ecm] forKey:@"has_ecm"];
|
|
[result setObject:[NSNumber numberWithBool:has_scoop] forKey:@"has_scoop"];
|
|
[result setObject:[NSNumber numberWithBool:has_energy_bomb] forKey:@"has_energy_bomb"];
|
|
[result setObject:[NSNumber numberWithBool:has_energy_unit] forKey:@"has_energy_unit"];
|
|
[result setObject:[NSNumber numberWithInt:energy_unit] forKey:@"energy_unit"];
|
|
[result setObject:[NSNumber numberWithBool:has_docking_computer] forKey:@"has_docking_computer"];
|
|
[result setObject:[NSNumber numberWithBool:has_galactic_hyperdrive] forKey:@"has_galactic_hyperdrive"];
|
|
[result setObject:[NSNumber numberWithBool:has_escape_pod] forKey:@"has_escape_pod"];
|
|
[result setObject:[NSNumber numberWithBool:has_fuel_injection] forKey:@"has_fuel_injection"];
|
|
NSMutableArray* missile_roles = [NSMutableArray arrayWithCapacity:max_missiles];
|
|
int i;
|
|
for (i = 0; i < max_missiles; i++)
|
|
{
|
|
if (missile_entity[i])
|
|
{
|
|
[missile_roles addObject:[missile_entity[i] roles]];
|
|
}
|
|
else
|
|
[missile_roles addObject:@"NONE"];
|
|
}
|
|
[result setObject:missile_roles forKey:@"missile_roles"];
|
|
[self safe_all_missiles];
|
|
//
|
|
[result setObject:[NSNumber numberWithInt:[self calc_missiles]] forKey:@"missiles"];
|
|
//
|
|
[result setObject:[NSNumber numberWithInt:legal_status] forKey:@"legal_status"];
|
|
[result setObject:[NSNumber numberWithInt:market_rnd] forKey:@"market_rnd"];
|
|
[result setObject:[NSNumber numberWithInt:ship_kills] forKey:@"ship_kills"];
|
|
[result setObject:[NSNumber numberWithBool:saved] forKey:@"saved"];
|
|
|
|
// ship depreciation
|
|
[result setObject:[NSNumber numberWithInt:ship_trade_in_factor] forKey:@"ship_trade_in_factor"];
|
|
|
|
// mission variables
|
|
if (mission_variables)
|
|
[result setObject:[NSDictionary dictionaryWithDictionary:mission_variables] forKey:@"mission_variables"];
|
|
|
|
// communications log
|
|
if (comm_log)
|
|
{
|
|
while ([comm_log count] > 200) // only keep the last 200 lines
|
|
[comm_log removeObjectAtIndex:0];
|
|
[result setObject:comm_log forKey:@"comm_log"];
|
|
}
|
|
|
|
// extra equipment flags
|
|
if (extra_equipment)
|
|
{
|
|
[self set_extra_equipment_from_flags];
|
|
[result setObject:[NSDictionary dictionaryWithDictionary:extra_equipment] forKey:@"extra_equipment"];
|
|
}
|
|
|
|
// reputation
|
|
[result setObject:reputation forKey:@"reputation"];
|
|
|
|
// passengers
|
|
[result setObject:[NSNumber numberWithInt:max_passengers] forKey:@"max_passengers"];
|
|
[result setObject:passengers forKey:@"passengers"];
|
|
[result setObject:passenger_record forKey:@"passenger_record"];
|
|
|
|
// contracts
|
|
[result setObject:contracts forKey:@"contracts"];
|
|
[result setObject:contract_record forKey:@"contract_record"];
|
|
|
|
//shipyard
|
|
[result setObject:shipyard_record forKey:@"shipyard_record"];
|
|
|
|
//ship's clock
|
|
[result setObject:[NSNumber numberWithDouble:ship_clock] forKey:@"ship_clock"];
|
|
|
|
//speech
|
|
[result setObject:[NSNumber numberWithBool:speech_on] forKey:@"speech_on"];
|
|
|
|
//ootunes
|
|
[result setObject:[NSNumber numberWithBool:ootunes_on] forKey:@"ootunes_on"];
|
|
|
|
//base ship description
|
|
[result setObject:ship_desc forKey:@"ship_desc"];
|
|
|
|
//local market
|
|
if ([docked_station localMarket])
|
|
[result setObject:[docked_station localMarket] forKey:@"localMarket"];
|
|
|
|
// reduced detail option
|
|
[result setObject:[NSNumber numberWithBool:[universe reducedDetail]] forKey:@"reducedDetail"];
|
|
|
|
// strict universe?
|
|
if ([universe strict])
|
|
{
|
|
[result setObject:[NSNumber numberWithBool:YES] forKey:@"strict"];
|
|
}
|
|
|
|
// persistant universe information
|
|
if ([universe local_planetinfo_overrides])
|
|
{
|
|
[result setObject:[universe local_planetinfo_overrides] forKey:@"local_planetinfo_overrides"];
|
|
}
|
|
|
|
// create checksum
|
|
clear_checksum();
|
|
munge_checksum(galaxy_seed.a); munge_checksum(galaxy_seed.b); munge_checksum(galaxy_seed.c);
|
|
munge_checksum(galaxy_seed.d); munge_checksum(galaxy_seed.e); munge_checksum(galaxy_seed.f);
|
|
munge_checksum((int)galaxy_coordinates.x); munge_checksum((int)galaxy_coordinates.y);
|
|
munge_checksum(credits); munge_checksum(fuel);
|
|
munge_checksum(max_cargo); munge_checksum(missiles);
|
|
munge_checksum(legal_status); munge_checksum(market_rnd); munge_checksum(ship_kills);
|
|
if (mission_variables)
|
|
munge_checksum([[mission_variables description] length]);
|
|
if (extra_equipment)
|
|
munge_checksum([[extra_equipment description] length]);
|
|
int final_checksum = munge_checksum([[ship_desc description] length]);
|
|
|
|
//set checksum
|
|
[result setObject:[NSNumber numberWithInt:final_checksum] forKey:@"checksum"];
|
|
|
|
//NSLog(@"Player Dictionary :\n%@",[result description]);
|
|
|
|
return [NSDictionary dictionaryWithDictionary:[result autorelease]];
|
|
}
|
|
|
|
- (void) setCommanderDataFromDictionary:(NSDictionary *) dict
|
|
{
|
|
if ([dict objectForKey:@"strict"])
|
|
{
|
|
if (![universe strict])
|
|
{
|
|
// reset to strict and reload player
|
|
NSLog(@"DEBUG loading a STRICT player dictionary ..1");
|
|
[universe setStrict:YES];
|
|
NSLog(@"DEBUG loading a STRICT player dictionary ..2");
|
|
// [self setCommanderDataFromDictionary:dict];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ([universe strict])
|
|
{
|
|
// reset to unrestricted and reload player
|
|
NSLog(@"DEBUG loading a UNRESTRICTED player dictionary ..1");
|
|
[universe setStrict:NO];
|
|
NSLog(@"DEBUG loading a UNRESTRICTED player dictionary ..2");
|
|
// [self setCommanderDataFromDictionary:dict];
|
|
}
|
|
}
|
|
//base ship description
|
|
if ([dict objectForKey:@"ship_desc"])
|
|
{
|
|
if (ship_desc) [ship_desc release];
|
|
ship_desc = [(NSString *)[dict objectForKey:@"ship_desc"] retain];
|
|
NSDictionary *ship_dict = [universe getDictionaryForShip:ship_desc];
|
|
if (ship_dict)
|
|
[self setUpShipFromDictionary:ship_dict];
|
|
}
|
|
|
|
// ship depreciation
|
|
if ([dict objectForKey:@"ship_trade_in_factor"])
|
|
ship_trade_in_factor = [(NSNumber*)[dict objectForKey:@"ship_trade_in_factor"] intValue];
|
|
else
|
|
ship_trade_in_factor = 75;
|
|
|
|
if ([dict objectForKey:@"galaxy_seed"])
|
|
{
|
|
NSArray *seed_vals = [(NSString *)[dict objectForKey:@"galaxy_seed"] componentsSeparatedByString:@" "];
|
|
galaxy_seed.a = (unsigned char)[(NSString *)[seed_vals objectAtIndex:0] intValue];
|
|
galaxy_seed.b = (unsigned char)[(NSString *)[seed_vals objectAtIndex:1] intValue];
|
|
galaxy_seed.c = (unsigned char)[(NSString *)[seed_vals objectAtIndex:2] intValue];
|
|
galaxy_seed.d = (unsigned char)[(NSString *)[seed_vals objectAtIndex:3] intValue];
|
|
galaxy_seed.e = (unsigned char)[(NSString *)[seed_vals objectAtIndex:4] intValue];
|
|
galaxy_seed.f = (unsigned char)[(NSString *)[seed_vals objectAtIndex:5] intValue];
|
|
}
|
|
|
|
if ([dict objectForKey:@"galaxy_coordinates"])
|
|
{
|
|
NSArray *coord_vals = [(NSString *)[dict objectForKey:@"galaxy_coordinates"] componentsSeparatedByString:@" "];
|
|
galaxy_coordinates.x = (unsigned char)[(NSString *)[coord_vals objectAtIndex:0] intValue];
|
|
galaxy_coordinates.y = (unsigned char)[(NSString *)[coord_vals objectAtIndex:1] intValue];
|
|
}
|
|
|
|
if ([dict objectForKey:@"player_name"])
|
|
{
|
|
if (player_name) [player_name release];
|
|
player_name = [(NSString *)[dict objectForKey:@"player_name"] retain];
|
|
}
|
|
|
|
if ([dict objectForKey:@"shipCommodityData"])
|
|
{
|
|
if (shipCommodityData) [shipCommodityData release];
|
|
shipCommodityData = [(NSArray *)[dict objectForKey:@"shipCommodityData"] retain];
|
|
}
|
|
|
|
// extra equipment flags
|
|
[extra_equipment removeAllObjects];
|
|
[self set_extra_equipment_from_flags];
|
|
if ([dict objectForKey:@"extra_equipment"])
|
|
{
|
|
[extra_equipment addEntriesFromDictionary:(NSDictionary *)[dict objectForKey:@"extra_equipment"]];
|
|
}
|
|
// bools (mostly deprecated by use of the extra_equipment dictionary, keep for compatibility)
|
|
//
|
|
if (([dict objectForKey:@"has_docking_computer"])&&([(NSNumber *)[dict objectForKey:@"has_docking_computer"] boolValue]))
|
|
[self add_extra_equipment:@"EQ_DOCK_COMP"];
|
|
if (([dict objectForKey:@"has_galactic_hyperdrive"])&&([(NSNumber *)[dict objectForKey:@"has_galactic_hyperdrive"] boolValue]))
|
|
[self add_extra_equipment:@"EQ_GAL_DRIVE"];
|
|
if (([dict objectForKey:@"has_escape_pod"])&&([(NSNumber *)[dict objectForKey:@"has_escape_pod"] boolValue]))
|
|
[self add_extra_equipment:@"EQ_ESCAPE_POD"];
|
|
if (([dict objectForKey:@"has_ecm"])&&([(NSNumber *)[dict objectForKey:@"has_ecm"] boolValue]))
|
|
[self add_extra_equipment:@"EQ_ECM"];
|
|
if (([dict objectForKey:@"has_scoop"])&&([(NSNumber *)[dict objectForKey:@"has_scoop"] boolValue]))
|
|
[self add_extra_equipment:@"EQ_FUEL_SCOOPS"];
|
|
if (([dict objectForKey:@"has_energy_bomb"])&&([(NSNumber *)[dict objectForKey:@"has_energy_bomb"] boolValue]))
|
|
[self add_extra_equipment:@"EQ_ENERGY_BOMB"];
|
|
//
|
|
if (([dict objectForKey:@"has_fuel_injection"])&&([(NSNumber *)[dict objectForKey:@"has_fuel_injection"] boolValue]))
|
|
[self add_extra_equipment:@"EQ_FUEL_INJECTION"];
|
|
if (([dict objectForKey:@"has_energy_unit"])&&([(NSNumber *)[dict objectForKey:@"has_energy_unit"] boolValue]))
|
|
{
|
|
if ([dict objectForKey:@"energy_unit"])
|
|
energy_unit = [(NSNumber *)[dict objectForKey:@"energy_unit"] intValue]; // load specials
|
|
else
|
|
energy_unit = (has_energy_unit) ? ENERGY_UNIT_NORMAL : ENERGY_UNIT_NONE; // set default
|
|
switch (energy_unit)
|
|
{
|
|
case ENERGY_UNIT_NORMAL :
|
|
[self add_extra_equipment:@"EQ_ENERGY_UNIT"];
|
|
break;
|
|
case ENERGY_UNIT_NAVAL :
|
|
[self add_extra_equipment:@"EQ_NAVAL_ENERGY_UNIT"];
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
}
|
|
|
|
// speech
|
|
if ([dict objectForKey:@"speech_on"])
|
|
speech_on = [(NSNumber *)[dict objectForKey:@"speech_on"] boolValue];
|
|
|
|
// reputation
|
|
if ([dict objectForKey:@"reputation"])
|
|
{
|
|
if (reputation)
|
|
[reputation release];
|
|
reputation = [[NSMutableDictionary dictionaryWithDictionary:(NSDictionary *)[dict objectForKey:@"reputation"]] retain];
|
|
}
|
|
|
|
// passengers
|
|
if ([dict objectForKey:@"max_passengers"])
|
|
max_passengers = [(NSNumber *)[dict objectForKey:@"max_passengers"] intValue];
|
|
else
|
|
max_passengers = 0;
|
|
if ([dict objectForKey:@"passengers"])
|
|
{
|
|
if (passengers)
|
|
[passengers release];
|
|
passengers = [[NSMutableArray arrayWithArray:(NSArray *)[dict objectForKey:@"passengers"]] retain];
|
|
}
|
|
else
|
|
{
|
|
if (passengers)
|
|
[passengers release];
|
|
passengers = [[NSMutableArray arrayWithCapacity:8] retain];
|
|
}
|
|
if ([dict objectForKey:@"passenger_record"])
|
|
{
|
|
if (passenger_record)
|
|
[passenger_record release];
|
|
passenger_record = [[NSMutableDictionary dictionaryWithDictionary:(NSDictionary *)[dict objectForKey:@"passenger_record"]] retain];
|
|
}
|
|
else
|
|
{
|
|
if (passenger_record)
|
|
[passenger_record release];
|
|
passenger_record = [[NSMutableDictionary dictionaryWithCapacity:8] retain];
|
|
}
|
|
|
|
// contracts
|
|
if ([dict objectForKey:@"contracts"])
|
|
{
|
|
if (contracts)
|
|
[contracts release];
|
|
contracts = [[NSMutableArray arrayWithArray:(NSArray *)[dict objectForKey:@"contracts"]] retain];
|
|
}
|
|
else
|
|
{
|
|
if (contracts)
|
|
[contracts release];
|
|
contracts = [[NSMutableArray arrayWithCapacity:8] retain];
|
|
}
|
|
if ([dict objectForKey:@"contract_record"])
|
|
{
|
|
if (contract_record)
|
|
[contract_record release];
|
|
contract_record = [[NSMutableDictionary dictionaryWithDictionary:(NSDictionary *)[dict objectForKey:@"contract_record"]] retain];
|
|
}
|
|
else
|
|
{
|
|
if (contract_record)
|
|
[contract_record release];
|
|
contract_record = [[NSMutableDictionary dictionaryWithCapacity:8] retain];
|
|
}
|
|
|
|
// shipyard
|
|
if ([dict objectForKey:@"shipyard_record"])
|
|
{
|
|
if (shipyard_record)
|
|
[shipyard_record release];
|
|
shipyard_record = [[NSMutableDictionary dictionaryWithDictionary:(NSDictionary *)[dict objectForKey:@"shipyard_record"]] retain];
|
|
}
|
|
else
|
|
{
|
|
if (shipyard_record)
|
|
[shipyard_record release];
|
|
shipyard_record = [[NSMutableDictionary dictionaryWithCapacity:4] retain];
|
|
}
|
|
|
|
// ootunes
|
|
if ([dict objectForKey:@"ootunes_on"])
|
|
ootunes_on = [(NSNumber *)[dict objectForKey:@"ootunes_on"] boolValue];
|
|
|
|
// reducedDetail
|
|
if ([dict objectForKey:@"reducedDetail"])
|
|
[universe setReducedDetail:[(NSNumber *)[dict objectForKey:@"reducedDetail"] boolValue]];
|
|
|
|
if ([dict objectForKey:@"saved"])
|
|
saved = [(NSNumber *)[dict objectForKey:@"saved"] boolValue];
|
|
|
|
// ints
|
|
//
|
|
int original_hold_size = [universe maxCargoForShip:ship_desc];
|
|
if ([dict objectForKey:@"max_cargo"])
|
|
max_cargo = [(NSNumber *)[dict objectForKey:@"max_cargo"] intValue];
|
|
if (max_cargo > original_hold_size)
|
|
[self add_extra_equipment:@"EQ_CARGO_BAY"];
|
|
max_cargo -= max_passengers * 5;
|
|
//
|
|
if ([dict objectForKey:@"credits"])
|
|
credits = [(NSNumber *)[dict objectForKey:@"credits"] intValue];
|
|
if ([dict objectForKey:@"fuel"])
|
|
fuel = [(NSNumber *)[dict objectForKey:@"fuel"] intValue];
|
|
//
|
|
if ([dict objectForKey:@"galaxy_number"])
|
|
galaxy_number = [(NSNumber *)[dict objectForKey:@"galaxy_number"] intValue];
|
|
if ([dict objectForKey:@"forward_weapon"])
|
|
forward_weapon = [(NSNumber *)[dict objectForKey:@"forward_weapon"] intValue];
|
|
if ([dict objectForKey:@"aft_weapon"])
|
|
aft_weapon = [(NSNumber *)[dict objectForKey:@"aft_weapon"] intValue];
|
|
if ([dict objectForKey:@"port_weapon"])
|
|
port_weapon = [(NSNumber *)[dict objectForKey:@"port_weapon"] intValue];
|
|
if ([dict objectForKey:@"starboard_weapon"])
|
|
starboard_weapon = [(NSNumber *)[dict objectForKey:@"starboard_weapon"] intValue];
|
|
//
|
|
if ([dict objectForKey:@"missiles"])
|
|
missiles = [(NSNumber *)[dict objectForKey:@"missiles"] intValue];
|
|
// sanity check the number of missiles...
|
|
if (missiles < 0)
|
|
missiles = 0;
|
|
if (missiles > max_missiles)
|
|
missiles = max_missiles;
|
|
// end sanity check
|
|
if ([dict objectForKey:@"legal_status"])
|
|
legal_status = [(NSNumber *)[dict objectForKey:@"legal_status"] intValue];
|
|
if ([dict objectForKey:@"market_rnd"])
|
|
market_rnd = [(NSNumber *)[dict objectForKey:@"market_rnd"] intValue];
|
|
if ([dict objectForKey:@"ship_kills"])
|
|
ship_kills = [(NSNumber *)[dict objectForKey:@"ship_kills"] intValue];
|
|
|
|
// doubles
|
|
//
|
|
if ([dict objectForKey:@"ship_clock"])
|
|
ship_clock = [(NSNumber*)[dict objectForKey:@"ship_clock"] doubleValue];
|
|
fps_check_time = ship_clock;
|
|
|
|
// mission_variables
|
|
[mission_variables removeAllObjects];
|
|
if ([dict objectForKey:@"mission_variables"])
|
|
[mission_variables addEntriesFromDictionary:(NSDictionary *)[dict objectForKey:@"mission_variables"]];
|
|
|
|
// persistant universe info
|
|
if ([dict objectForKey:@"local_planetinfo_overrides"])
|
|
{
|
|
[universe setLocal_planetinfo_overrides:(NSDictionary *)[dict objectForKey:@"local_planetinfo_overrides"]];
|
|
}
|
|
|
|
// communications log
|
|
if ([dict objectForKey:@"comm_log"])
|
|
{
|
|
if (comm_log) [comm_log release];
|
|
comm_log = [[NSMutableArray alloc] initWithArray:(NSArray*)[dict objectForKey:@"comm_log"]]; // retained
|
|
}
|
|
|
|
// set up missiles
|
|
int i;
|
|
[self setActive_missile: 0];
|
|
for (i = 0; i < SHIPENTITY_MAX_MISSILES; i++)
|
|
{
|
|
if (missile_entity[i])
|
|
[missile_entity[i] release];
|
|
missile_entity[i] = nil;
|
|
}
|
|
if ([dict objectForKey:@"missile_roles"])
|
|
{
|
|
NSArray* missile_roles = (NSArray*)[dict objectForKey:@"missile_roles"];
|
|
if (max_missiles < [missile_roles count])
|
|
missile_roles = [missile_roles subarrayWithRange:NSMakeRange(0, max_missiles)];
|
|
// if (missiles != [missile_roles count])
|
|
if ((missiles) && (missiles != [missile_roles count]))
|
|
missiles = [missile_roles count]; // sanity check the number of missiles
|
|
for (i = 0; (i < max_missiles)&&(i < [missile_roles count]); i++)
|
|
{
|
|
NSString* missile_desc = (NSString*)[missile_roles objectAtIndex:i];
|
|
if (![missile_desc isEqual:@"NONE"])
|
|
{
|
|
missile_entity[i] = [universe getShipWithRole:missile_desc]; // retain count = 1
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < missiles; i++)
|
|
missile_entity[i] = [universe getShipWithRole:@"EQ_MISSILE"]; // retain count = 1
|
|
}
|
|
while ((missiles > 0)&&(missile_entity[active_missile] == nil))
|
|
[self select_next_missile];
|
|
//
|
|
|
|
//
|
|
[self set_flags_from_extra_equipment];
|
|
forward_shield = PLAYER_MAX_FORWARD_SHIELD;
|
|
aft_shield = PLAYER_MAX_AFT_SHIELD;
|
|
//
|
|
|
|
// things...
|
|
//
|
|
system_seed = [universe findSystemAtCoords:galaxy_coordinates withGalaxySeed:galaxy_seed];
|
|
target_system_seed = system_seed;
|
|
cursor_coordinates = galaxy_coordinates;
|
|
//
|
|
|
|
// finally
|
|
missiles = [self calc_missiles];
|
|
|
|
// [universe removeAllEntitiesExceptPlayer:NO]; // reset the universe outside the station
|
|
// [universe setSystemTo:system_seed];
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
- (id) init
|
|
{
|
|
self = [super init];
|
|
//
|
|
compass_mode = COMPASS_MODE_BASIC;
|
|
//
|
|
//
|
|
afterburnerSoundLooping = NO;
|
|
//
|
|
int i;
|
|
for (i = 0; i < SHIPENTITY_MAX_MISSILES; i++)
|
|
missile_entity[i] = nil;
|
|
[self set_up];
|
|
//
|
|
drawDebugParticle = [[ParticleEntity alloc] init];
|
|
[drawDebugParticle setParticleType:PARTICLE_MARKER];
|
|
//
|
|
isPlayer = YES;
|
|
//
|
|
return self;
|
|
}
|
|
|
|
static BOOL galactic_witchjump;
|
|
- (void) set_up
|
|
{
|
|
int i;
|
|
Random_Seed gal_seed = {0x4a, 0x5a, 0x48, 0x02, 0x53, 0xb7};
|
|
//
|
|
showDemoShips = NO;
|
|
//
|
|
|
|
if (ship_desc)
|
|
[ship_desc release];
|
|
ship_desc = [[NSString stringWithString:PLAYER_SHIP_DESC] retain];
|
|
ship_trade_in_factor = 75;
|
|
//
|
|
NSDictionary *huddict = [ResourceManager dictionaryFromFilesNamed:@"hud.plist" inFolder:@"Config" andMerge:YES];
|
|
if (hud)
|
|
[hud release];
|
|
hud = [[HeadUpDisplay alloc] initWithDictionary:huddict];
|
|
[hud setPlayer:self];
|
|
[hud setScannerZoom:1.0];
|
|
//
|
|
script = [[ResourceManager dictionaryFromFilesNamed:@"script.plist" inFolder:@"Config" andMerge:YES] retain];
|
|
mission_variables =[[NSMutableDictionary dictionaryWithCapacity:16] retain];
|
|
[self setScript_target:nil];
|
|
[self resetMissionChoice];
|
|
//
|
|
reputation = [[NSMutableDictionary alloc] initWithCapacity:6];
|
|
[reputation setObject:[NSNumber numberWithInt:0] forKey:CONTRACTS_GOOD_KEY];
|
|
[reputation setObject:[NSNumber numberWithInt:0] forKey:CONTRACTS_BAD_KEY];
|
|
[reputation setObject:[NSNumber numberWithInt:7] forKey:CONTRACTS_UNKNOWN_KEY];
|
|
[reputation setObject:[NSNumber numberWithInt:0] forKey:PASSAGE_GOOD_KEY];
|
|
[reputation setObject:[NSNumber numberWithInt:0] forKey:PASSAGE_BAD_KEY];
|
|
[reputation setObject:[NSNumber numberWithInt:7] forKey:PASSAGE_UNKNOWN_KEY];
|
|
//
|
|
max_passengers = 0;
|
|
if (passengers)
|
|
[passengers release];
|
|
passengers = [[NSMutableArray alloc] initWithCapacity:8];
|
|
if (passenger_record)
|
|
[passenger_record release];
|
|
passenger_record = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
|
|
//
|
|
if (contracts)
|
|
[contracts release];
|
|
contracts = [[NSMutableArray alloc] initWithCapacity:8];
|
|
if (contract_record)
|
|
[contract_record release];
|
|
contract_record = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
|
|
//
|
|
if (shipyard_record)
|
|
[shipyard_record release];
|
|
shipyard_record = [[NSMutableDictionary dictionaryWithCapacity:4] retain];
|
|
//
|
|
if (extra_equipment)
|
|
[extra_equipment release];
|
|
extra_equipment =[[NSMutableDictionary dictionaryWithCapacity:16] retain];
|
|
//
|
|
missionBackgroundImage = nil;
|
|
//
|
|
script_time = 0.0;
|
|
script_time_check = SCRIPT_TIMER_INTERVAL;
|
|
script_time_interval = SCRIPT_TIMER_INTERVAL;
|
|
//
|
|
NSCalendarDate *nowDate = [NSCalendarDate calendarDate];
|
|
ship_clock = PLAYER_SHIP_CLOCK_START;
|
|
ship_clock += [nowDate hourOfDay] * 3600.0;
|
|
ship_clock += [nowDate minuteOfHour] * 60.0;
|
|
ship_clock += [nowDate secondOfMinute];
|
|
fps_check_time = ship_clock;
|
|
ship_clock_adjust = 0.0;
|
|
//
|
|
speech_on = NO;
|
|
ootunes_on = NO;
|
|
//
|
|
mouse_control_on = NO;
|
|
//
|
|
docking_music_on = YES;
|
|
//
|
|
if (name)
|
|
[name release];
|
|
name = [[NSString stringWithString:@"Player"] retain];
|
|
rolling = NO;
|
|
pitching = NO;
|
|
galactic_witchjump = NO;
|
|
//
|
|
flight_speed = 0.0;
|
|
max_flight_speed = 160.0;
|
|
max_flight_roll = 2.0;
|
|
max_flight_pitch = 1.0;
|
|
//
|
|
// control factors
|
|
//
|
|
thrust = 32.0;
|
|
roll_delta = 2.0 * max_flight_roll;
|
|
pitch_delta = 2.0 * max_flight_pitch;
|
|
//
|
|
displayListName = 0;
|
|
//
|
|
status = STATUS_TEST;
|
|
forward_shield = PLAYER_MAX_FORWARD_SHIELD;
|
|
aft_shield = PLAYER_MAX_AFT_SHIELD;
|
|
energy = 256;
|
|
weapon_temp = 0.0;
|
|
forward_weapon_temp = 0.0;
|
|
aft_weapon_temp = 0.0;
|
|
port_weapon_temp = 0.0;
|
|
starboard_weapon_temp = 0.0;
|
|
cabin_temp = 60.0;
|
|
alert_flags = 0;
|
|
//
|
|
game_over = NO;
|
|
docked = NO;
|
|
finished = NO;
|
|
bomb_detonated = NO;
|
|
has_docking_computer = NO;
|
|
autopilot_engaged = NO;
|
|
afterburner_engaged = NO;
|
|
hyperspeed_engaged = NO;
|
|
hyperspeed_locked = NO;
|
|
//
|
|
ident_engaged = NO;
|
|
//
|
|
ecm_in_operation = NO;
|
|
ecm_start_time = 0.0;
|
|
//
|
|
fuel_leak_rate = 0.0;
|
|
//
|
|
witchspaceCountdown = 0.0;
|
|
//
|
|
// release sounds
|
|
//
|
|
if (beepSound) [beepSound release];
|
|
if (boopSound) [boopSound release];
|
|
if (weaponSound) [weaponSound release];
|
|
if (weaponHitSound) [weaponHitSound release];
|
|
if (damageSound) [damageSound release];
|
|
if (scrapeDamageSound) [scrapeDamageSound release];
|
|
if (destructionSound) [destructionSound release];
|
|
if (breakPatternSound) [breakPatternSound release];
|
|
//
|
|
if (ecmSound) [ecmSound release];
|
|
if (buySound) [buySound release];
|
|
if (sellSound) [sellSound release];
|
|
if (warningSound) [warningSound release];
|
|
if (afterburner1Sound) [afterburner1Sound release];
|
|
if (afterburner2Sound) [afterburner2Sound release];
|
|
//
|
|
if (themeMusic) [themeMusic release];
|
|
if (missionMusic) [missionMusic release];
|
|
if (dockingMusic) [dockingMusic release];
|
|
//
|
|
// allocate sounds
|
|
//
|
|
beepSound = [[ResourceManager soundNamed:@"beep.aiff" inFolder:@"Sounds"] retain];
|
|
boopSound = [[ResourceManager soundNamed:@"boop.aiff" inFolder:@"Sounds"] retain];
|
|
weaponSound = [[ResourceManager soundNamed:@"laser.aiff" inFolder:@"Sounds"] retain];
|
|
weaponHitSound = [[ResourceManager soundNamed:@"laserhits.aiff" inFolder:@"Sounds"] retain];
|
|
missileSound = [[ResourceManager soundNamed:@"missile.aiff" inFolder:@"Sounds"] retain];
|
|
damageSound = [[ResourceManager soundNamed:@"hit.aiff" inFolder:@"Sounds"] retain];
|
|
scrapeDamageSound = [[ResourceManager soundNamed:@"hullbang.aiff" inFolder:@"Sounds"] retain];
|
|
destructionSound = [[ResourceManager soundNamed:@"bigbang.aiff" inFolder:@"Sounds"] retain];
|
|
breakPatternSound = [[ResourceManager soundNamed:@"breakpattern.aiff" inFolder:@"Sounds"] retain];
|
|
//
|
|
ecmSound = [[ResourceManager soundNamed:@"ecm.aiff" inFolder:@"Sounds"] retain];
|
|
buySound = [[ResourceManager soundNamed:@"buy.aiff" inFolder:@"Sounds"] retain];
|
|
sellSound = [[ResourceManager soundNamed:@"sell.aiff" inFolder:@"Sounds"] retain];
|
|
warningSound = [[ResourceManager soundNamed:@"warning.aiff" inFolder:@"Sounds"] retain];
|
|
afterburner1Sound = [[ResourceManager soundNamed:@"afterburner1.aiff" inFolder:@"Sounds"] retain];
|
|
afterburner2Sound = [[ResourceManager soundNamed:@"afterburner2.aiff" inFolder:@"Sounds"] retain];
|
|
//
|
|
|
|
// //// for looping sounds set the sound's delegate to self
|
|
// //
|
|
// [afterburner1Sound setDelegate:self];
|
|
// [afterburner2Sound setDelegate:self];
|
|
|
|
//
|
|
themeMusic = [[ResourceManager movieFromFilesNamed:@"OoliteTheme.ogg" inFolder:@"Music"] retain];
|
|
missionMusic = [[ResourceManager movieFromFilesNamed:@"OoliteTheme.ogg" inFolder:@"Music"] retain];
|
|
dockingMusic = [[ResourceManager movieFromFilesNamed:@"BlueDanube.ogg" inFolder:@"Music"] retain];
|
|
//
|
|
collision_radius = 50.0;
|
|
//
|
|
[self setModel:PLAYER_MODEL];
|
|
//
|
|
shot_time = 0.0;
|
|
shot_counter = 0;
|
|
//
|
|
if (shipAI) [shipAI release];
|
|
shipAI = [[AI alloc] initWithStateMachine:AI_DOCKING_COMPUTER andState:@"GLOBAL"]; // alloc retains dealloc'd by ShipEntity
|
|
[shipAI setOwner:self];
|
|
//
|
|
|
|
// player commander data
|
|
//
|
|
player_name = [[NSString alloc] initWithString:@"Jameson"]; // alloc retains
|
|
galaxy_coordinates = NSMakePoint(0x14,0xAD); // 20,173
|
|
galaxy_seed = gal_seed;
|
|
credits = 1000;
|
|
fuel = PLAYER_MAX_FUEL;
|
|
fuel_accumulator = 0.0;
|
|
|
|
galaxy_number = 0;
|
|
forward_weapon = WEAPON_PULSE_LASER;
|
|
aft_weapon = WEAPON_NONE;
|
|
port_weapon = WEAPON_NONE;
|
|
starboard_weapon = WEAPON_NONE;
|
|
|
|
max_cargo = 20; // will be reset later
|
|
|
|
shipCommodityData = [(NSArray *)[(NSDictionary *)[ResourceManager dictionaryFromFilesNamed:@"commodities.plist" inFolder:@"Config" andMerge:YES] objectForKey:@"default"] retain];
|
|
|
|
has_ecm = NO;
|
|
has_scoop = NO;
|
|
has_energy_bomb = NO;
|
|
has_energy_unit = NO;
|
|
has_docking_computer = NO;
|
|
has_galactic_hyperdrive = NO;
|
|
has_escape_pod = NO;
|
|
has_fuel_injection = NO;
|
|
|
|
shield_booster = 1;
|
|
shield_enhancer = 0;
|
|
|
|
// set up missiles
|
|
missiles = PLAYER_STARTING_MISSILES;
|
|
max_missiles = PLAYER_MAX_MISSILES;
|
|
[self setActive_missile: 0];
|
|
for (i = 0; i < missiles; i++)
|
|
{
|
|
if (missile_entity[i])
|
|
[missile_entity[i] release];
|
|
missile_entity[i] = [universe getShipWithRole:@"EQ_MISSILE"]; // retain count = 1
|
|
}
|
|
[self safe_all_missiles];
|
|
|
|
legal_status = 0;
|
|
|
|
market_rnd = 0;
|
|
ship_kills = 0;
|
|
saved = NO;
|
|
cursor_coordinates = galaxy_coordinates;
|
|
|
|
[self init_keys];
|
|
|
|
scan_class = CLASS_PLAYER;
|
|
|
|
[universe clearGUIs];
|
|
|
|
docked_station = [universe station];
|
|
|
|
if (comm_log) [comm_log release];
|
|
comm_log = [[NSMutableArray alloc] initWithCapacity:200]; // retained
|
|
//
|
|
|
|
if (specialCargo)
|
|
[specialCargo release];
|
|
specialCargo = nil;
|
|
}
|
|
|
|
- (void) setUpShipFromDictionary:(NSDictionary *) dict
|
|
{
|
|
//NSLog(@"DEBUG Playerentity - setUpShipFromDictionary:(NSDictionary *) dict");
|
|
//
|
|
// set things from dictionary from here out
|
|
//
|
|
if ([dict objectForKey:@"max_flight_speed"])
|
|
max_flight_speed = [(NSNumber *)[dict objectForKey:@"max_flight_speed"] doubleValue];
|
|
if ([dict objectForKey:@"max_flight_roll"])
|
|
max_flight_roll = [(NSNumber *)[dict objectForKey:@"max_flight_roll"] doubleValue];
|
|
if ([dict objectForKey:@"max_flight_pitch"])
|
|
max_flight_pitch = [(NSNumber *)[dict objectForKey:@"max_flight_pitch"] doubleValue];
|
|
//
|
|
if ([dict objectForKey:@"thrust"])
|
|
{
|
|
thrust = [(NSNumber *)[dict objectForKey:@"thrust"] doubleValue];
|
|
// speed_delta = thrust;
|
|
}
|
|
//
|
|
if ([dict objectForKey:@"max_energy"])
|
|
max_energy = [(NSNumber *)[dict objectForKey:@"max_energy"] doubleValue];
|
|
if ([dict objectForKey:@"energy_recharge_rate"])
|
|
energy_recharge_rate = [(NSNumber *)[dict objectForKey:@"energy_recharge_rate"] doubleValue];
|
|
energy = max_energy;
|
|
//
|
|
if ([dict objectForKey:@"forward_weapon_type"])
|
|
{
|
|
NSString *weapon_type_string = (NSString *)[dict objectForKey:@"forward_weapon_type"];
|
|
if ([weapon_type_string isEqual:@"WEAPON_PULSE_LASER"])
|
|
forward_weapon_type = WEAPON_PULSE_LASER;
|
|
if ([weapon_type_string isEqual:@"WEAPON_BEAM_LASER"])
|
|
forward_weapon_type = WEAPON_BEAM_LASER;
|
|
if ([weapon_type_string isEqual:@"WEAPON_MINING_LASER"])
|
|
forward_weapon_type = WEAPON_MINING_LASER;
|
|
if ([weapon_type_string isEqual:@"WEAPON_MILITARY_LASER"])
|
|
forward_weapon_type = WEAPON_MILITARY_LASER;
|
|
if ([weapon_type_string isEqual:@"WEAPON_THARGOID_LASER"])
|
|
forward_weapon_type = WEAPON_THARGOID_LASER;
|
|
if ([weapon_type_string isEqual:@"WEAPON_PLASMA_CANNON"])
|
|
forward_weapon_type = WEAPON_PLASMA_CANNON;
|
|
if ([weapon_type_string isEqual:@"WEAPON_NONE"])
|
|
forward_weapon_type = WEAPON_NONE;
|
|
}
|
|
//
|
|
if ([dict objectForKey:@"missiles"])
|
|
missiles = [(NSNumber *)[dict objectForKey:@"missiles"] intValue];
|
|
if ([dict objectForKey:@"has_ecm"])
|
|
has_ecm = [(NSNumber *)[dict objectForKey:@"has_ecm"] boolValue];
|
|
if ([dict objectForKey:@"has_scoop"])
|
|
has_scoop = [(NSNumber *)[dict objectForKey:@"has_scoop"] boolValue];
|
|
if ([dict objectForKey:@"has_escape_pod"])
|
|
has_escape_pod = [(NSNumber *)[dict objectForKey:@"has_escape_pod"] boolValue];
|
|
//
|
|
if ([dict objectForKey:@"max_cargo"])
|
|
max_cargo = [(NSNumber *)[dict objectForKey:@"max_cargo"] intValue];
|
|
//
|
|
// A HACK!! - must do this before the model is set
|
|
if ([dict objectForKey:@"smooth"])
|
|
is_smooth_shaded = YES;
|
|
else
|
|
is_smooth_shaded = NO;
|
|
//
|
|
if ([dict objectForKey:@"model"])
|
|
[self setModel:(NSString *)[dict objectForKey:@"model"]];
|
|
//
|
|
if ([dict objectForKey:KEY_NAME])
|
|
{
|
|
if (name)
|
|
[name release];
|
|
name = [[NSString stringWithString:(NSString *)[dict objectForKey:KEY_NAME]] retain];
|
|
}
|
|
//
|
|
if ([dict objectForKey:@"roles"])
|
|
{
|
|
if (roles)
|
|
[roles release];
|
|
roles = [[NSString stringWithString:(NSString *)[dict objectForKey:@"roles"]] retain];
|
|
}
|
|
//
|
|
if ([dict objectForKey:@"laser_color"])
|
|
{
|
|
NSString *laser_color_string = (NSString *)[dict objectForKey:@"laser_color"];
|
|
SEL color_selector = NSSelectorFromString(laser_color_string);
|
|
if ([NSColor respondsToSelector:color_selector])
|
|
{
|
|
id color_thing = [NSColor performSelector:color_selector];
|
|
if ([color_thing isKindOfClass:[NSColor class]])
|
|
[self setLaserColor:(NSColor *)color_thing];
|
|
}
|
|
}
|
|
else
|
|
[self setLaserColor:[NSColor redColor]];
|
|
//
|
|
if ([dict objectForKey:@"extra_equipment"])
|
|
{
|
|
[extra_equipment removeAllObjects];
|
|
[extra_equipment addEntriesFromDictionary:(NSDictionary *)[dict objectForKey:@"extra_equipment"]];
|
|
}
|
|
//
|
|
if ([dict objectForKey:@"max_missiles"])
|
|
{
|
|
// NSLog(@"DEBUG setting max_missiles %@",[dict objectForKey:@"max_missiles"]);
|
|
max_missiles = [(NSNumber *)[dict objectForKey:@"max_missiles"] intValue];
|
|
}
|
|
//
|
|
if ([dict objectForKey:@"hud"])
|
|
{
|
|
//NSLog(@"DEBUG setting hud %@",[dict objectForKey:@"hud"]);
|
|
NSString *hud_desc = (NSString *)[dict objectForKey:@"hud"];
|
|
NSDictionary *huddict = [ResourceManager dictionaryFromFilesNamed:hud_desc inFolder:@"Config" andMerge:YES];
|
|
if (huddict)
|
|
{
|
|
if (hud) [hud release];
|
|
hud = [[HeadUpDisplay alloc] initWithDictionary:huddict];
|
|
[hud setPlayer:self];
|
|
[hud setScannerZoom:1.0];
|
|
}
|
|
}
|
|
//
|
|
|
|
// set up missiles
|
|
int i;
|
|
for (i = 0; i < SHIPENTITY_MAX_MISSILES; i++)
|
|
{
|
|
if (missile_entity[i])
|
|
[missile_entity[i] release];
|
|
missile_entity[i] = nil;
|
|
}
|
|
for (i = 0; i < missiles; i++)
|
|
missile_entity[i] = [universe getShipWithRole:@"EQ_MISSILE"]; // retain count = 1
|
|
[self setActive_missile: 0];
|
|
//
|
|
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
if (ship_desc) [ship_desc release];
|
|
|
|
if (hud) [hud release];
|
|
|
|
if (comm_log) [comm_log release];
|
|
|
|
if (script) [script release];
|
|
if (mission_variables) [mission_variables release];
|
|
if (lastTextKey) [lastTextKey release];
|
|
|
|
if (extra_equipment) [extra_equipment release];
|
|
|
|
if (reputation) [reputation release];
|
|
if (passengers) [passengers release];
|
|
if (passenger_record) [passenger_record release];
|
|
if (contracts) [contracts release];
|
|
if (contract_record) [contract_record release];
|
|
if (shipyard_record) [shipyard_record release];
|
|
|
|
if (beepSound) [beepSound release];
|
|
if (boopSound) [boopSound release];
|
|
if (weaponSound) [weaponSound release];
|
|
if (weaponHitSound) [weaponHitSound release];
|
|
if (missileSound) [missileSound release];
|
|
if (damageSound) [damageSound release];
|
|
if (scrapeDamageSound) [scrapeDamageSound release];
|
|
if (destructionSound) [destructionSound release];
|
|
if (breakPatternSound) [breakPatternSound release];
|
|
//
|
|
if (ecmSound) [ecmSound release];
|
|
if (buySound) [buySound release];
|
|
if (sellSound) [sellSound release];
|
|
if (warningSound) [warningSound release];
|
|
if (afterburner1Sound) [afterburner1Sound release];
|
|
if (afterburner2Sound) [afterburner2Sound release];
|
|
|
|
if (themeMusic) [themeMusic release];
|
|
if (missionMusic) [missionMusic release];
|
|
if (dockingMusic) [dockingMusic release];
|
|
|
|
if (missionBackgroundImage) [missionBackgroundImage release];
|
|
|
|
if (player_name) [player_name release];
|
|
if (shipCommodityData) [shipCommodityData release];
|
|
|
|
if (specialCargo) [specialCargo release];
|
|
|
|
int i;
|
|
for (i = 0; i < SHIPENTITY_MAX_MISSILES; i++)
|
|
{
|
|
if (missile_entity[i])
|
|
[missile_entity[i] release];
|
|
}
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
|
|
- (void) warnAboutHostiles
|
|
{
|
|
// make a warningSound
|
|
// NSLog(@"player warned about hostiles!");
|
|
#ifdef HAVE_SOUND
|
|
if (![warningSound isPlaying])
|
|
[warningSound play];
|
|
#endif
|
|
}
|
|
|
|
- (BOOL) canCollide
|
|
{
|
|
switch (status)
|
|
{
|
|
case STATUS_IN_FLIGHT :
|
|
case STATUS_AUTOPILOT_ENGAGED :
|
|
case STATUS_WITCHSPACE_COUNTDOWN :
|
|
return YES;
|
|
break;
|
|
|
|
case STATUS_DEAD :
|
|
case STATUS_ESCAPE_SEQUENCE :
|
|
default :
|
|
return NO;
|
|
}
|
|
}
|
|
|
|
- (NSComparisonResult) compareZeroDistance:(Entity *)otherEntity;
|
|
{
|
|
return NSOrderedDescending; // always the most near
|
|
}
|
|
|
|
- (void) update:(double) delta_t
|
|
{
|
|
// update flags
|
|
//
|
|
has_moved = ((position.x != last_position.x)||(position.y != last_position.y)||(position.z != last_position.z));
|
|
last_position = position;
|
|
has_rotated = ((q_rotation.w != last_q_rotation.w)||(q_rotation.x != last_q_rotation.x)||(q_rotation.y != last_q_rotation.y)||(q_rotation.z != last_q_rotation.z));
|
|
last_q_rotation = q_rotation;
|
|
|
|
// update timers
|
|
//
|
|
shot_time += delta_t;
|
|
script_time += delta_t;
|
|
ship_clock += delta_t;
|
|
if (ship_clock_adjust != 0.0) // adjust for coming out of warp (add LY * LY hrs)
|
|
{
|
|
double fine_adjust = delta_t * 7200.0;
|
|
if (ship_clock_adjust > 86400) // more than a day
|
|
fine_adjust = delta_t * 115200.0; // 16 times faster
|
|
if (ship_clock_adjust > 0)
|
|
{
|
|
if (fine_adjust > ship_clock_adjust)
|
|
fine_adjust = ship_clock_adjust;
|
|
ship_clock += fine_adjust;
|
|
ship_clock_adjust -= fine_adjust;
|
|
}
|
|
else
|
|
{
|
|
if (fine_adjust < ship_clock_adjust)
|
|
fine_adjust = ship_clock_adjust;
|
|
ship_clock -= fine_adjust;
|
|
ship_clock_adjust += fine_adjust;
|
|
}
|
|
}
|
|
|
|
//fps
|
|
if (ship_clock > fps_check_time)
|
|
{
|
|
fps_counter = floor(1.0 / delta_t);
|
|
fps_check_time = ship_clock + 0.25;
|
|
}
|
|
|
|
// scripting
|
|
if (script_time > script_time_check)
|
|
{
|
|
[self checkScript];
|
|
script_time_check += script_time_interval;
|
|
}
|
|
|
|
// deal with collisions
|
|
//
|
|
[self manageCollisions];
|
|
[self saveToLastFrame];
|
|
|
|
[self pollControls:delta_t];
|
|
|
|
if ((status == STATUS_DEMO)&&(gui_screen != GUI_SCREEN_INTRO1)&&(gui_screen != GUI_SCREEN_INTRO2)&&(gui_screen != GUI_SCREEN_MISSION)&&(gui_screen != GUI_SCREEN_SHIPYARD))
|
|
[self setGuiToIntro1Screen]; //set up demo mode
|
|
|
|
if ((status == STATUS_AUTOPILOT_ENGAGED)||(status == STATUS_ESCAPE_SEQUENCE))
|
|
{
|
|
[super update:delta_t];
|
|
[self doBookkeeping:delta_t];
|
|
return;
|
|
}
|
|
|
|
if (!docked_station)
|
|
{
|
|
// do flight routines
|
|
//
|
|
|
|
//// velocity stuff
|
|
//
|
|
velocity.x += momentum.x / mass; momentum.x = 0;
|
|
velocity.y += momentum.y / mass; momentum.y = 0;
|
|
velocity.z += momentum.z / mass; momentum.z = 0;
|
|
//
|
|
position.x += delta_t*velocity.x;
|
|
position.y += delta_t*velocity.y;
|
|
position.z += delta_t*velocity.z;
|
|
//
|
|
if (velocity.x > 0.0)
|
|
velocity.x -= (velocity.x > delta_t*thrust) ? delta_t*thrust : velocity.x;
|
|
if (velocity.y > 0.0)
|
|
velocity.y -= (velocity.y > delta_t*thrust) ? delta_t*thrust : velocity.y;
|
|
if (velocity.z > 0.0)
|
|
velocity.z -= (velocity.z > delta_t*thrust) ? delta_t*thrust : velocity.z;
|
|
if (velocity.x < 0.0)
|
|
velocity.x -= (velocity.x < -delta_t*thrust) ? -delta_t*thrust : velocity.x;
|
|
if (velocity.y < 0.0)
|
|
velocity.y -= (velocity.y < -delta_t*thrust) ? -delta_t*thrust : velocity.y;
|
|
if (velocity.z < 0.0)
|
|
velocity.z -= (velocity.z < -delta_t*thrust) ? -delta_t*thrust : velocity.z;
|
|
//
|
|
// if ((velocity.x != 0)||(velocity.y != 0)||(velocity.z != 0))
|
|
// NSLog(@"Player velocity [ %.3f, %.3f, %.3f]", velocity.x, velocity.y, velocity.z);
|
|
//
|
|
////
|
|
|
|
[self applyRoll:delta_t*flight_roll andClimb:delta_t*flight_pitch];
|
|
[self moveForward:delta_t*flight_speed];
|
|
}
|
|
|
|
if (status == STATUS_IN_FLIGHT)
|
|
{
|
|
[self doBookkeeping:delta_t];
|
|
}
|
|
|
|
if (status == STATUS_LAUNCHING)
|
|
{
|
|
if ([universe breakPatternOver])
|
|
{
|
|
// time to check the script!
|
|
[self checkScript];
|
|
// next check in 10s
|
|
|
|
status = STATUS_IN_FLIGHT;
|
|
}
|
|
}
|
|
|
|
if (status == STATUS_WITCHSPACE_COUNTDOWN)
|
|
{
|
|
[self doBookkeeping:delta_t];
|
|
witchspaceCountdown -= delta_t;
|
|
if (witchspaceCountdown < 0.0) witchspaceCountdown = 0.0;
|
|
if (galactic_witchjump)
|
|
[universe displayCountdownMessage:[NSString stringWithFormat:[universe expandDescription:@"[witch-galactic-in-f-seconds]" forSystem:system_seed], witchspaceCountdown] forCount:1.0];
|
|
else
|
|
[universe displayCountdownMessage:[NSString stringWithFormat:[universe expandDescription:@"[witch-to-@-in-f-seconds]" forSystem:system_seed], [universe getSystemName:target_system_seed], witchspaceCountdown] forCount:1.0];
|
|
if (witchspaceCountdown == 0.0)
|
|
{
|
|
[self safe_all_missiles];
|
|
if (galactic_witchjump)
|
|
[self enterGalacticWitchspace];
|
|
else
|
|
[self enterWitchspace];
|
|
}
|
|
}
|
|
|
|
if (status == STATUS_EXITING_WITCHSPACE)
|
|
{
|
|
if ([universe breakPatternOver])
|
|
{
|
|
// time to check the script!
|
|
[self checkScript];
|
|
// next check in 10s
|
|
[self resetScriptTimer]; // reset the in-system timer
|
|
|
|
// announce arrival
|
|
if ([universe planet])
|
|
[universe addMessage:[NSString stringWithFormat:@" %@. ",[universe getSystemName:system_seed]] forCount:3.0];
|
|
else
|
|
// [universe addMessage:@"Witchspace engine malfunction!" forCount:3.0];
|
|
[universe addMessage:[universe expandDescription:@"[witch-engine-malfunction]" forSystem:system_seed] forCount:3.0];
|
|
|
|
status = STATUS_IN_FLIGHT;
|
|
}
|
|
}
|
|
|
|
if (status == STATUS_DOCKING)
|
|
{
|
|
if ([universe breakPatternOver])
|
|
{
|
|
[self docked]; // bookkeeping for docking
|
|
}
|
|
}
|
|
|
|
if ((status == STATUS_DEAD)&&(shot_time > 30.0))
|
|
{
|
|
[universe game_over]; // we restart the universe
|
|
}
|
|
|
|
//
|
|
// check for lost ident target and ensure the ident system is actually scanning
|
|
//
|
|
if (ident_engaged)
|
|
{
|
|
if (missile_status == MISSILE_STATUS_TARGET_LOCKED)
|
|
{
|
|
Entity* e = [universe entityForUniversalID:primaryTarget];
|
|
if ((e == nil)||(e->zero_distance > SCANNER_MAX_RANGE2)||(e->scan_class == CLASS_NO_DRAW)) // checking scanClass checks for cloaked ships
|
|
{
|
|
[universe addMessage:[universe expandDescription:@"[target-lost]" forSystem:system_seed] forCount:3.0];
|
|
#ifdef HAVE_SOUND
|
|
[boopSound play];
|
|
#endif
|
|
primaryTarget = NO_TARGET;
|
|
missile_status = MISSILE_STATUS_SAFE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
missile_status = MISSILE_STATUS_ARMED;
|
|
}
|
|
}
|
|
|
|
//
|
|
// check each unlaunched missile's target still exists and is in-range
|
|
//
|
|
int i;
|
|
for (i = 0; i < max_missiles; i++)
|
|
{
|
|
if ((missile_entity[i])&&([missile_entity[i] getPrimaryTargetID] != NO_TARGET))
|
|
{
|
|
ShipEntity* target_ship = (ShipEntity *)[missile_entity[i] getPrimaryTarget];
|
|
if ((!target_ship)||(target_ship->zero_distance > SCANNER_MAX_RANGE2))
|
|
{
|
|
[universe addMessage:[universe expandDescription:@"[target-lost]" forSystem:system_seed] forCount:3.0];
|
|
#ifdef HAVE_SOUND
|
|
[boopSound play];
|
|
#endif
|
|
[missile_entity[i] removeTarget:nil];
|
|
if ((i == active_missile)&&(!ident_engaged))
|
|
{
|
|
primaryTarget = NO_TARGET;
|
|
missile_status = MISSILE_STATUS_SAFE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((missile_status == MISSILE_STATUS_ARMED)&&(ident_engaged||[[missile_entity[active_missile] roles] hasSuffix:@"MISSILE"])&&((status == STATUS_IN_FLIGHT)||(status == STATUS_WITCHSPACE_COUNTDOWN)))
|
|
{
|
|
int first_target_id = [universe getFirstEntityTargettedFromEntity:self inView:[universe viewDir]];
|
|
if (first_target_id != NO_TARGET)
|
|
{
|
|
Entity *first_target = [universe entityForUniversalID:first_target_id];
|
|
if ([first_target isKindOfClass:[ShipEntity class]])
|
|
{
|
|
primaryTarget = first_target_id;
|
|
missile_status = MISSILE_STATUS_TARGET_LOCKED;
|
|
if ((missile_entity[active_missile])&&(!ident_engaged))
|
|
[missile_entity[active_missile] addTarget:first_target];
|
|
[universe addMessage:[NSString stringWithFormat:[universe expandDescription:@"[@-locked-onto-@]" forSystem:system_seed], (ident_engaged)? @"Ident system": @"Missile", [(ShipEntity *)first_target name]] forCount:4.5];
|
|
#ifdef HAVE_SOUND
|
|
[beepSound play];
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) doBookkeeping:(double) delta_t
|
|
{
|
|
// Bookeeping;
|
|
//
|
|
double speed_delta = 5.0 * thrust;
|
|
//
|
|
PlanetEntity* sun = [universe sun];
|
|
// if (weapon_temp > 0.0)
|
|
// {
|
|
// weapon_temp -= WEAPON_COOLING_FACTOR * delta_t;
|
|
// if (weapon_temp < 0.0)
|
|
// weapon_temp = 0.0;
|
|
// }
|
|
// cool all weapons
|
|
//
|
|
if (forward_weapon_temp > 0.0)
|
|
{
|
|
forward_weapon_temp -= WEAPON_COOLING_FACTOR * delta_t;
|
|
if (forward_weapon_temp < 0.0)
|
|
forward_weapon_temp = 0.0;
|
|
}
|
|
if (aft_weapon_temp > 0.0)
|
|
{
|
|
aft_weapon_temp -= WEAPON_COOLING_FACTOR * delta_t;
|
|
if (aft_weapon_temp < 0.0)
|
|
aft_weapon_temp = 0.0;
|
|
}
|
|
if (port_weapon_temp > 0.0)
|
|
{
|
|
port_weapon_temp -= WEAPON_COOLING_FACTOR * delta_t;
|
|
if (port_weapon_temp < 0.0)
|
|
port_weapon_temp = 0.0;
|
|
}
|
|
if (starboard_weapon_temp > 0.0)
|
|
{
|
|
starboard_weapon_temp -= WEAPON_COOLING_FACTOR * delta_t;
|
|
if (starboard_weapon_temp < 0.0)
|
|
starboard_weapon_temp = 0.0;
|
|
}
|
|
// copy new temp to main temp
|
|
//
|
|
switch ([universe viewDir])
|
|
{
|
|
case VIEW_DOCKED:
|
|
case VIEW_NONE:
|
|
case VIEW_BREAK_PATTERN:
|
|
case VIEW_FORWARD:
|
|
weapon_temp = forward_weapon_temp;
|
|
break;
|
|
case VIEW_AFT:
|
|
weapon_temp = aft_weapon_temp;
|
|
break;
|
|
case VIEW_PORT:
|
|
weapon_temp = port_weapon_temp;
|
|
break;
|
|
case VIEW_STARBOARD:
|
|
weapon_temp = starboard_weapon_temp;
|
|
break;
|
|
}
|
|
|
|
// cloaking device
|
|
if (has_cloaking_device)
|
|
{
|
|
if (cloaking_device_active)
|
|
{
|
|
energy -= delta_t * CLOAKING_DEVICE_ENERGY_RATE;
|
|
if (energy < CLOAKING_DEVICE_MIN_ENERGY)
|
|
[self deactivateCloakingDevice];
|
|
}
|
|
else
|
|
{
|
|
if (energy < max_energy)
|
|
{
|
|
energy += delta_t * CLOAKING_DEVICE_ENERGY_RATE;
|
|
if (energy > max_energy)
|
|
energy = max_energy;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (energy < max_energy)
|
|
{
|
|
double energy_multiplier = 1.0 + 0.1 * energy_unit; // 1.5x recharge with normal energy unit, 2x with naval!
|
|
energy += energy_recharge_rate * energy_multiplier * delta_t;
|
|
if (energy > max_energy)
|
|
energy = max_energy;
|
|
}
|
|
if (forward_shield < PLAYER_MAX_FORWARD_SHIELD)
|
|
{
|
|
forward_shield += SHIELD_RECHARGE_FACTOR * delta_t;
|
|
energy -= SHIELD_RECHARGE_FACTOR * delta_t;
|
|
if (forward_shield > PLAYER_MAX_FORWARD_SHIELD)
|
|
{
|
|
energy += forward_shield - PLAYER_MAX_FORWARD_SHIELD;
|
|
forward_shield = PLAYER_MAX_FORWARD_SHIELD;
|
|
}
|
|
}
|
|
if (aft_shield < PLAYER_MAX_AFT_SHIELD)
|
|
{
|
|
aft_shield += SHIELD_RECHARGE_FACTOR * delta_t;
|
|
energy -= SHIELD_RECHARGE_FACTOR * delta_t;
|
|
if (aft_shield > PLAYER_MAX_FORWARD_SHIELD)
|
|
{
|
|
energy += aft_shield - PLAYER_MAX_AFT_SHIELD;
|
|
aft_shield = PLAYER_MAX_AFT_SHIELD;
|
|
}
|
|
}
|
|
if (ecm_in_operation)
|
|
{
|
|
if (energy > 0.0)
|
|
energy -= ECM_ENERGY_DRAIN_FACTOR * delta_t; // drain energy because of the ECM
|
|
else
|
|
{
|
|
ecm_in_operation = NO;
|
|
[ecmSound stop];
|
|
//[universe displayMessage:@"ECM system deactivated (no energy left)." forCount:3.0];
|
|
[universe addMessage:[universe expandDescription:@"[ecm-out-of-juice]" forSystem:system_seed] forCount:3.0];
|
|
}
|
|
if ([universe getTime] > ecm_start_time + ECM_DURATION)
|
|
{
|
|
ecm_in_operation = NO;
|
|
}
|
|
}
|
|
|
|
if (sun)
|
|
{
|
|
// do Revised sun-skimming check here...
|
|
double sun_zd = sun->zero_distance; // square of distance
|
|
double sun_cr = sun->collision_radius;
|
|
double alt1 = sun_cr * sun_cr / sun_zd;
|
|
double external_temp = SUN_TEMPERATURE * alt1;
|
|
if ([[universe sun] goneNova])
|
|
external_temp *= 100;
|
|
if (external_temp < 60.0)
|
|
external_temp = 60.0;
|
|
if (external_temp > cabin_temp)
|
|
{
|
|
//NSLog(@"DEBUG sun skim >>>> sun alt1 = %.3f ext temp = %.3f", alt1, external_temp);
|
|
cabin_temp += (external_temp - cabin_temp) * delta_t * CABIN_INSULATION_FACTOR;
|
|
}
|
|
else
|
|
cabin_temp += (external_temp - cabin_temp) * delta_t * CABIN_COOLING_FACTOR;
|
|
|
|
if (([self has_extra_equipment:@"EQ_FUEL_SCOOPS"])&&(alt1 > 0.75)&&(fuel < 70))
|
|
{
|
|
fuel_accumulator += delta_t * flight_speed * 0.010;
|
|
while (fuel_accumulator > 1.0)
|
|
{
|
|
fuel ++;
|
|
fuel_accumulator -= 1.0;
|
|
}
|
|
if (fuel > 70) fuel = 70;
|
|
[universe displayMessage:@"Fuel Scoop Active" forCount:1.0];
|
|
}
|
|
}
|
|
|
|
if (cabin_temp > PLAYER_MAX_CABIN_TEMP)
|
|
[self getDestroyed];
|
|
|
|
if ((status == STATUS_ESCAPE_SEQUENCE)&&(shot_time > ESCAPE_SEQUENCE_TIME))
|
|
{
|
|
[(ShipEntity *)[universe entityForUniversalID:found_target] becomeExplosion]; // blow up the doppelganger
|
|
[self setTargetToStation];
|
|
if ([self getPrimaryTarget])
|
|
{
|
|
// restore player ship
|
|
ShipEntity *player_ship = [universe getShip: ship_desc]; // retained
|
|
[self setModel:[player_ship getModel]];
|
|
[player_ship release]; // we only wanted it for its polygons!
|
|
[universe setViewDirection:VIEW_FORWARD];
|
|
[self enterDock:(StationEntity *)[self getPrimaryTarget]];
|
|
}
|
|
}
|
|
////
|
|
//
|
|
// MOVED THE FOLLOWING FROM PLAYERENTITY POLLFLIGHTCONTROLS:
|
|
travelling_at_hyperspeed = (flight_speed > max_flight_speed);
|
|
if (hyperspeed_engaged)
|
|
{
|
|
// increase speed up to maximum hyperspeed
|
|
if (flight_speed < max_flight_speed * HYPERSPEED_FACTOR)
|
|
flight_speed += speed_delta * delta_t * HYPERSPEED_FACTOR;
|
|
if (flight_speed > max_flight_speed * HYPERSPEED_FACTOR)
|
|
flight_speed = max_flight_speed * HYPERSPEED_FACTOR;
|
|
|
|
// check for mass lock
|
|
hyperspeed_locked = [self massLocked];
|
|
|
|
if (hyperspeed_locked)
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if (![boopSound isPlaying])
|
|
[boopSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[jump-mass-locked]" forSystem:system_seed] forCount:4.5];
|
|
hyperspeed_engaged = NO;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (afterburner_engaged)
|
|
{
|
|
if (flight_speed < max_flight_speed * AFTERBURNER_FACTOR)
|
|
flight_speed += speed_delta * delta_t * AFTERBURNER_FACTOR;
|
|
if (flight_speed > max_flight_speed * AFTERBURNER_FACTOR)
|
|
flight_speed = max_flight_speed * AFTERBURNER_FACTOR;
|
|
fuel_accumulator -= delta_t * AFTERBURNER_BURNRATE;
|
|
while ((fuel_accumulator < 0)&&(fuel > 0))
|
|
{
|
|
fuel_accumulator += 1.0;
|
|
fuel --;
|
|
if (fuel <= 0)
|
|
afterburner_engaged = NO;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// slow back down...
|
|
if (travelling_at_hyperspeed)
|
|
{
|
|
// decrease speed to maximum normal speed
|
|
flight_speed -= speed_delta * delta_t * HYPERSPEED_FACTOR;
|
|
if (flight_speed < max_flight_speed)
|
|
flight_speed = max_flight_speed;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
////
|
|
|
|
if ((fuel_leak_rate > 0.0)&&(fuel > 0))
|
|
{
|
|
fuel_accumulator -= fuel_leak_rate * delta_t;
|
|
while ((fuel_accumulator < 0)&&(fuel > 0))
|
|
{
|
|
fuel_accumulator += 1.0;
|
|
fuel--;
|
|
}
|
|
if (fuel == 0)
|
|
fuel_leak_rate = 0;
|
|
}
|
|
}
|
|
|
|
- (void) applyRoll:(GLfloat) roll1 andClimb:(GLfloat) climb1
|
|
{
|
|
quaternion_rotate_about_z( &q_rotation, -roll1);
|
|
quaternion_rotate_about_x( &q_rotation, -climb1);
|
|
|
|
quaternion_normalise(&q_rotation); // probably not strictly necessary but good to do to keep q_rotation sane
|
|
quaternion_into_gl_matrix(q_rotation, rotMatrix);
|
|
|
|
v_right.x = rotMatrix[0];
|
|
v_right.y = rotMatrix[4];
|
|
v_right.z = rotMatrix[8];
|
|
|
|
v_up.x = rotMatrix[1];
|
|
v_up.y = rotMatrix[5];
|
|
v_up.z = rotMatrix[9];
|
|
|
|
v_forward.x = rotMatrix[2];
|
|
v_forward.y = rotMatrix[6];
|
|
v_forward.z = rotMatrix[10];
|
|
}
|
|
|
|
- (void) moveForward:(double) amount
|
|
{
|
|
distance_travelled += amount;
|
|
position.x += amount * v_forward.x;
|
|
position.y += amount * v_forward.y;
|
|
position.z += amount * v_forward.z;
|
|
}
|
|
|
|
|
|
// return a point 36u back from the front of the ship
|
|
// this equates with the centre point of a cobra mk3
|
|
//
|
|
- (Vector) getViewpointPosition
|
|
{
|
|
Vector viewpoint = position;
|
|
float offset;
|
|
switch ([universe viewDir])
|
|
{
|
|
case VIEW_FORWARD:
|
|
offset = boundingBox.max_z - 36.0;
|
|
viewpoint.x += offset * v_forward.x; viewpoint.y += offset * v_forward.y; viewpoint.z += offset * v_forward.z;
|
|
break;
|
|
case VIEW_AFT:
|
|
offset = boundingBox.min_z + 36.0;
|
|
viewpoint.x += offset * v_forward.x; viewpoint.y += offset * v_forward.y; viewpoint.z += offset * v_forward.z;
|
|
break;
|
|
case VIEW_PORT:
|
|
offset = boundingBox.min_x + 36.0;
|
|
viewpoint.x += offset * v_right.x; viewpoint.y += offset * v_right.y; viewpoint.z += offset * v_right.z;
|
|
break;
|
|
case VIEW_STARBOARD:
|
|
offset = boundingBox.max_x - 36.0;
|
|
viewpoint.x += offset * v_right.x; viewpoint.y += offset * v_right.y; viewpoint.z += offset * v_right.z;
|
|
break;
|
|
}
|
|
return viewpoint;
|
|
}
|
|
|
|
- (void) drawEntity:(BOOL) immediate :(BOOL) translucent
|
|
{
|
|
|
|
/*--
|
|
// NSLog(@"DEBUG checking per poly collision Player versus %@ %d", [other name], [other universal_id]);
|
|
|
|
// Matrix rMat;
|
|
// rMat[0] = v_forward;
|
|
// rMat[1] = v_up;
|
|
// rMat[2] = v_right;
|
|
|
|
Quaternion q_actual = q_rotation;
|
|
q_actual.w = -q_actual.w; // reverse rotation
|
|
|
|
gl_matrix rMatrix;
|
|
quaternion_into_gl_matrix( q_actual, rMatrix);
|
|
|
|
// DEBUG - TEMPORARY
|
|
// return YES;
|
|
|
|
glPopMatrix();
|
|
glPushMatrix();
|
|
|
|
// glTranslatef( position.x, position.y, position.z);
|
|
// glMultMatrixf( rMatrix);
|
|
|
|
int v;
|
|
for (v = 0; v < n_vertices; v++)
|
|
{
|
|
Vector v0 = vertices[v];
|
|
|
|
// Vector p0 = make_vector( 3.0 * v0.x, 3.0 * v0.y, 3.0 * v0.z);
|
|
|
|
mult_vector_gl_matrix(&v0, rMatrix);
|
|
// mult_vector(&v0, rMat);
|
|
|
|
Vector q0 = make_vector( position.x + 3.0 * v0.x, position.y + 3.0 * v0.y, position.z + 3.0 * v0.z);
|
|
glTranslatef( q0.x, q0.y, q0.z);
|
|
|
|
// glPushMatrix();
|
|
// glTranslatef( p0.x, p0.y, p0.z);
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glVertex3i(0,0,0); glVertex3i(0,1,0); glVertex3i(1,1,0); glVertex3i(1,0,0);
|
|
glVertex3i(0,0,0); glVertex3i(1,0,0); glVertex3i(1,1,0); glVertex3i(0,1,0);
|
|
glVertex3i(0,0,0); glVertex3i(0,0,1); glVertex3i(0,1,1); glVertex3i(0,1,0);
|
|
glVertex3i(0,0,0); glVertex3i(0,1,0); glVertex3i(0,1,1); glVertex3i(0,0,1);
|
|
glVertex3i(0,0,0); glVertex3i(0,0,1); glVertex3i(1,0,1); glVertex3i(1,0,0);
|
|
glVertex3i(0,0,0); glVertex3i(1,0,0); glVertex3i(1,0,1); glVertex3i(0,0,1);
|
|
|
|
glEnd();
|
|
|
|
// glPopMatrix();
|
|
}
|
|
|
|
--*/
|
|
checkGLErrors([NSString stringWithFormat:@"after drawing Entity %@", self]);
|
|
}
|
|
|
|
- (void) drawCollisionHitIndicator:(NSDictionary *) info depth:(GLfloat)z1
|
|
{
|
|
// NSLog(@"DEBUG PlayerEntity drawCollisionHitIndicator");
|
|
|
|
int x = HIT_INDICATOR_CENTRE_X;
|
|
int y = HIT_INDICATOR_CENTRE_Y;
|
|
double alpha = 1.0;
|
|
if ([info objectForKey:X_KEY])
|
|
x = [(NSNumber *)[info objectForKey:X_KEY] intValue];
|
|
if ([info objectForKey:Y_KEY])
|
|
y = [(NSNumber *)[info objectForKey:Y_KEY] intValue];
|
|
if ([info objectForKey:ALPHA_KEY])
|
|
alpha = [(NSNumber *)[info objectForKey:ALPHA_KEY] doubleValue];
|
|
|
|
Vector scale = make_vector (1.0, 1.0, 0.0);
|
|
|
|
// x = 0; y = 0;
|
|
|
|
int fi;
|
|
glColor4f( 0.0, 1.0, 0.0, alpha); // green
|
|
for (fi = 0; fi < n_faces; fi++)
|
|
{
|
|
Vector v0 = vertices[faces[fi].vertex[0]];
|
|
Vector v1 = vertices[faces[fi].vertex[1]];
|
|
Vector v2 = vertices[faces[fi].vertex[2]];
|
|
Vector vv0 = make_vector( x + v0.x * scale.x, y + v0.z * scale.y, z1 + v0.y * scale.z);
|
|
Vector vv1 = make_vector( x + v1.x * scale.x, y + v1.z * scale.y, z1 + v1.y * scale.z);
|
|
Vector vv2 = make_vector( x + v2.x * scale.x, y + v2.z * scale.y, z1 + v2.y * scale.z);
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
glVertex3f( vv0.x, vv0.y, vv0.z); glVertex3f( vv1.x, vv1.y, vv1.z); glVertex3f( vv2.x, vv2.y, vv2.z);
|
|
glEnd();
|
|
}
|
|
glColor4f( 1.0, 0.0, 0.0, alpha); // red
|
|
for (fi = 0; fi < n_faces; fi++)
|
|
{
|
|
if (face_hit[fi])
|
|
{
|
|
Vector v0 = vertices[faces[fi].vertex[0]];
|
|
Vector v1 = vertices[faces[fi].vertex[1]];
|
|
Vector v2 = vertices[faces[fi].vertex[2]];
|
|
Vector vv0 = make_vector( x + v0.x * scale.x, y + v0.z * scale.y, z1 + v0.y * scale.z);
|
|
Vector vv1 = make_vector( x + v1.x * scale.x, y + v1.z * scale.y, z1 + v1.y * scale.z);
|
|
Vector vv2 = make_vector( x + v2.x * scale.x, y + v2.z * scale.y, z1 + v2.y * scale.z);
|
|
glBegin(GL_TRIANGLES);
|
|
glVertex3f( vv0.x, vv0.y, vv0.z); glVertex3f( vv1.x, vv1.y, vv1.z); glVertex3f( vv2.x, vv2.y, vv2.z);
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
- (BOOL) massLocked
|
|
{
|
|
return ((alert_flags & ALERT_FLAG_MASS_LOCK) != 0);
|
|
}
|
|
|
|
- (BOOL) atHyperspeed
|
|
{
|
|
return travelling_at_hyperspeed;
|
|
}
|
|
|
|
- (Vector) velocityVector
|
|
{
|
|
Vector result = v_forward;
|
|
result.x *= flight_speed;
|
|
result.y *= flight_speed;
|
|
result.z *= flight_speed;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// dial routines = all return 0.0 .. 1.0 or -1.0 .. 1.0
|
|
//
|
|
- (NSString *) ship_desc
|
|
{
|
|
return ship_desc;
|
|
}
|
|
|
|
- (StationEntity *) docked_station
|
|
{
|
|
return docked_station;
|
|
}
|
|
|
|
- (HeadUpDisplay *) hud
|
|
{
|
|
return hud;
|
|
}
|
|
|
|
- (void) setShowDemoShips:(BOOL) value
|
|
{
|
|
showDemoShips = value;
|
|
}
|
|
|
|
- (BOOL) showDemoShips
|
|
{
|
|
return showDemoShips || (status == STATUS_DEMO);
|
|
}
|
|
|
|
- (double) dial_roll
|
|
{
|
|
return flight_roll/max_flight_roll;
|
|
}
|
|
- (double) dial_pitch
|
|
{
|
|
return flight_pitch/max_flight_pitch;
|
|
}
|
|
- (double) dial_speed
|
|
{
|
|
if (flight_speed < max_flight_speed)
|
|
return flight_speed/max_flight_speed;
|
|
else
|
|
return 1.0;
|
|
}
|
|
- (double) dial_hyper_speed
|
|
{
|
|
return flight_speed/max_flight_speed;
|
|
}
|
|
|
|
- (double) dial_forward_shield
|
|
{
|
|
return forward_shield / PLAYER_MAX_FORWARD_SHIELD;
|
|
}
|
|
- (double) dial_aft_shield
|
|
{
|
|
return aft_shield / PLAYER_MAX_AFT_SHIELD;
|
|
}
|
|
|
|
- (double) dial_energy
|
|
{
|
|
return energy / max_energy;
|
|
}
|
|
|
|
- (double) dial_max_energy
|
|
{
|
|
return max_energy;
|
|
}
|
|
|
|
- (double) dial_fuel
|
|
{
|
|
return fuel / PLAYER_MAX_FUEL;
|
|
}
|
|
- (double) dial_cabin_temp
|
|
{
|
|
return cabin_temp / PLAYER_MAX_CABIN_TEMP;
|
|
}
|
|
- (double) dial_weapon_temp
|
|
{
|
|
return weapon_temp / PLAYER_MAX_WEAPON_TEMP;
|
|
}
|
|
- (double) dial_altitude
|
|
{
|
|
PlanetEntity *planet = [universe planet];
|
|
PlanetEntity *sun = [universe sun];
|
|
double planet_zd = (planet)? planet->zero_distance : PLAYER_SUPER_ALTITUDE2;
|
|
double sun_zd = (sun)? sun->zero_distance : PLAYER_SUPER_ALTITUDE2;
|
|
double planet_cr = (planet)? planet->collision_radius : 0;
|
|
double sun_cr = (sun)? sun->collision_radius : 0;
|
|
double alt = (planet_zd < sun_zd) ? (sqrt(planet_zd) - planet_cr) : (sqrt(sun_zd) - sun_cr);
|
|
|
|
alt /= PLAYER_DIAL_MAX_ALTITUDE;
|
|
|
|
if (alt > 1.0)
|
|
alt = 1.0;
|
|
if (alt < 0.0)
|
|
alt = 0.0;
|
|
|
|
return alt;
|
|
}
|
|
|
|
- (NSString*) dial_clock
|
|
{
|
|
int days = floor(ship_clock / 86400.0); // days
|
|
int secs = floor(ship_clock - days * 86400.0);
|
|
int hrs = floor(secs / 3600.0); // hrs
|
|
secs %= 3600;
|
|
int mins = floor(secs / 60.0); // mins
|
|
secs %= 60;
|
|
if (ship_clock_adjust == 0.0)
|
|
return [NSString stringWithFormat:@"%07d:%02d:%02d:%02d", days, hrs, mins, secs];
|
|
else
|
|
return [NSString stringWithFormat:@"%07d:%02d:%02d:%02d (adjusting)", days, hrs, mins, secs];
|
|
}
|
|
|
|
- (NSString*) dial_clock_adjusted
|
|
{
|
|
double ship_time = ship_clock + ship_clock_adjust;
|
|
int days = floor(ship_time / 86400.0); // days
|
|
int secs = floor(ship_time - days * 86400.0);
|
|
int hrs = floor(secs / 3600.0); // hrs
|
|
secs %= 3600;
|
|
int mins = floor(secs / 60.0); // mins
|
|
secs %= 60;
|
|
return [NSString stringWithFormat:@"%07d:%02d:%02d:%02d", days, hrs, mins, secs];
|
|
}
|
|
|
|
- (NSString*) dial_fpsinfo
|
|
{
|
|
return [NSString stringWithFormat:@"FPS: %3d", fps_counter];
|
|
}
|
|
|
|
- (NSString*) dial_objinfo
|
|
{
|
|
return [NSString stringWithFormat:@"Objs: %3d", [universe obj_count]];
|
|
}
|
|
|
|
- (int) dial_missiles
|
|
{
|
|
return missiles;
|
|
}
|
|
|
|
- (int) calc_missiles
|
|
{
|
|
int n_missiles = 0;
|
|
int i;
|
|
for (i = 0; i < max_missiles; i++)
|
|
{
|
|
if (missile_entity[i])
|
|
n_missiles++;
|
|
}
|
|
return n_missiles;
|
|
}
|
|
|
|
- (int) dial_missile_status
|
|
{
|
|
return missile_status;
|
|
}
|
|
|
|
- (NSMutableArray*) comm_log
|
|
{
|
|
return comm_log;
|
|
}
|
|
|
|
- (int) compass_mode
|
|
{
|
|
return compass_mode;
|
|
}
|
|
|
|
- (void) setCompass_mode:(int) value
|
|
{
|
|
compass_mode = value;
|
|
}
|
|
|
|
- (void) setNextCompassMode
|
|
{
|
|
if COMPASS_MODE_ADVANCED_OKAY
|
|
{
|
|
switch (compass_mode)
|
|
{
|
|
case COMPASS_MODE_PLANET:
|
|
if ([self checkForAegis] == AEGIS_NONE)
|
|
[self setCompass_mode:COMPASS_MODE_SUN];
|
|
else
|
|
[self setCompass_mode:COMPASS_MODE_STATION];
|
|
break;
|
|
case COMPASS_MODE_STATION:
|
|
[self setCompass_mode:COMPASS_MODE_SUN];
|
|
break;
|
|
case COMPASS_MODE_SUN:
|
|
if ([self getPrimaryTarget])
|
|
[self setCompass_mode:COMPASS_MODE_TARGET];
|
|
else
|
|
{
|
|
nextBeaconID = [[universe firstBeacon] universal_id];
|
|
if (nextBeaconID != NO_TARGET)
|
|
[self setCompass_mode:COMPASS_MODE_BEACONS];
|
|
else
|
|
[self setCompass_mode:COMPASS_MODE_PLANET];
|
|
}
|
|
break;
|
|
case COMPASS_MODE_TARGET:
|
|
nextBeaconID = [[universe firstBeacon] universal_id];
|
|
if (nextBeaconID != NO_TARGET)
|
|
[self setCompass_mode:COMPASS_MODE_BEACONS];
|
|
else
|
|
[self setCompass_mode:COMPASS_MODE_PLANET];
|
|
break;
|
|
case COMPASS_MODE_BEACONS:
|
|
nextBeaconID = [(ShipEntity*)[universe entityForUniversalID:nextBeaconID] nextBeaconID];
|
|
if (nextBeaconID == NO_TARGET)
|
|
[self setCompass_mode:COMPASS_MODE_PLANET];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (int) active_missile
|
|
{
|
|
return active_missile;
|
|
}
|
|
|
|
- (void) setActive_missile: (int) value
|
|
{
|
|
active_missile = value;
|
|
}
|
|
|
|
- (int) dial_max_missiles
|
|
{
|
|
return max_missiles;
|
|
}
|
|
|
|
- (BOOL) dial_ident_engaged
|
|
{
|
|
return ident_engaged;
|
|
}
|
|
|
|
- (NSString *) dial_target_name
|
|
{
|
|
Entity* target_entity = [universe entityForUniversalID:primaryTarget];
|
|
if ((target_entity)&&(target_entity->isShip))
|
|
return [(ShipEntity*)target_entity name];
|
|
else
|
|
return @"No target";
|
|
}
|
|
|
|
- (ShipEntity *) missile_for_station: (int) value
|
|
{
|
|
if ((value < 0)||(value >= max_missiles))
|
|
return nil;
|
|
return missile_entity[value];
|
|
}
|
|
|
|
- (void) sort_missiles
|
|
{
|
|
//
|
|
// puts all missiles into the first available slots
|
|
//
|
|
int i;
|
|
missiles = [self calc_missiles];
|
|
for (i = 0; i < missiles; i++)
|
|
{
|
|
if (missile_entity[i] == nil)
|
|
{
|
|
int j;
|
|
for (j = i + 1; j < max_missiles; j++)
|
|
{
|
|
if (missile_entity[j])
|
|
{
|
|
missile_entity[i] = missile_entity[j];
|
|
missile_entity[j] = nil;
|
|
j = max_missiles;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) safe_all_missiles
|
|
{
|
|
//
|
|
// sets all missile targets to NO_TARGET
|
|
//
|
|
int i;
|
|
for (i = 0; i < max_missiles; i++)
|
|
{
|
|
if (missile_entity[i])
|
|
[missile_entity[i] removeTarget:nil];
|
|
}
|
|
missile_status = MISSILE_STATUS_SAFE;
|
|
}
|
|
|
|
- (void) select_next_missile
|
|
{
|
|
int i;
|
|
for (i = 1; i < max_missiles; i++)
|
|
{
|
|
int next_missile = (active_missile + i) % max_missiles;
|
|
if (missile_entity[next_missile])
|
|
{
|
|
// if this is a missile then select it
|
|
// if ([[missile_entity[next_missile] roles] isEqual:@"EQ_MISSILE"])
|
|
if (missile_entity[next_missile]) // if it exists
|
|
{
|
|
[self setActive_missile:next_missile];
|
|
if (([[missile_entity[next_missile] roles] hasSuffix:@"MISSILE"])&&([missile_entity[next_missile] getPrimaryTarget] != nil))
|
|
{
|
|
// copy the missile's target
|
|
[self addTarget:[missile_entity[next_missile] getPrimaryTarget]];
|
|
missile_status = MISSILE_STATUS_TARGET_LOCKED;
|
|
}
|
|
else
|
|
missile_status = MISSILE_STATUS_SAFE;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- (void) clearAlert_flags
|
|
{
|
|
alert_flags = 0;
|
|
}
|
|
|
|
- (void) setAlert_flag:(int) flag :(BOOL) value
|
|
{
|
|
if (value)
|
|
{
|
|
alert_flags |= flag;
|
|
}
|
|
else
|
|
{
|
|
int comp = ~flag;
|
|
alert_flags &= comp;
|
|
}
|
|
}
|
|
|
|
- (int) alert_condition
|
|
{
|
|
int old_alert_condition = alert_condition;
|
|
alert_condition = ALERT_CONDITION_GREEN;
|
|
[self setAlert_flag:ALERT_FLAG_DOCKED :(status == STATUS_DOCKED)];
|
|
if (alert_flags & ALERT_FLAG_DOCKED)
|
|
{
|
|
alert_condition = ALERT_CONDITION_DOCKED;
|
|
}
|
|
else
|
|
{
|
|
if (alert_flags != 0)
|
|
alert_condition = ALERT_CONDITION_YELLOW;
|
|
if (alert_flags > ALERT_FLAG_YELLOW_LIMIT)
|
|
alert_condition = ALERT_CONDITION_RED;
|
|
}
|
|
if ((alert_condition == ALERT_CONDITION_RED)&&(old_alert_condition < ALERT_CONDITION_RED))
|
|
{
|
|
// give an audible warning
|
|
// NSLog(@"WARNING! %d %x", alert_condition, alert_flags);
|
|
#ifdef HAVE_SOUND
|
|
if ([warningSound isPlaying])
|
|
[warningSound stop];
|
|
[warningSound play];
|
|
#endif
|
|
}
|
|
|
|
return alert_condition;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
- (void) pollControls:(double) delta_t
|
|
{
|
|
MyOpenGLView *gameView = (MyOpenGLView *)[universe gameView];
|
|
|
|
if (gameView)
|
|
{
|
|
// poll the gameView keyboard things
|
|
[self pollApplicationControls]; // quit command-f etc.
|
|
switch (status)
|
|
{
|
|
case STATUS_WITCHSPACE_COUNTDOWN :
|
|
case STATUS_IN_FLIGHT :
|
|
[self pollFlightControls:delta_t];
|
|
break;
|
|
|
|
case STATUS_DEAD :
|
|
[self pollGameOverControls:delta_t];
|
|
break;
|
|
|
|
case STATUS_AUTOPILOT_ENGAGED :
|
|
[self pollAutopilotControls:delta_t];
|
|
break;
|
|
|
|
case STATUS_DOCKED :
|
|
[self pollDockedControls:delta_t];
|
|
break;
|
|
|
|
case STATUS_DEMO :
|
|
if (gui_screen == GUI_SCREEN_SHIPYARD)
|
|
{
|
|
[self pollGuiScreenControls];
|
|
[self pollGuiArrowKeyControls:delta_t];
|
|
}
|
|
else
|
|
[self pollDemoControls:delta_t];
|
|
break;
|
|
|
|
case STATUS_ESCAPE_SEQUENCE :
|
|
default :
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//static BOOL fuel_inject_pressed;
|
|
static BOOL jump_pressed;
|
|
static BOOL pause_pressed;
|
|
static BOOL zoom_pressed;
|
|
static BOOL compass_mode_pressed;
|
|
static BOOL next_target_pressed;
|
|
static BOOL fire_missile_pressed;
|
|
static BOOL target_missile_pressed;
|
|
static BOOL ident_pressed;
|
|
static BOOL safety_pressed;
|
|
static BOOL cloak_pressed;
|
|
- (void) pollFlightControls:(double) delta_t
|
|
{
|
|
MyOpenGLView *gameView = (MyOpenGLView *)[universe gameView];
|
|
BOOL paused = [[gameView gameController] game_is_paused];
|
|
double speed_delta = 5.0 * thrust;
|
|
|
|
if (!paused)
|
|
{
|
|
//
|
|
// arrow keys
|
|
//
|
|
if ([universe displayGUI])
|
|
[self pollGuiArrowKeyControls:delta_t];
|
|
else
|
|
[self pollFlightArrowKeyControls:delta_t];
|
|
//
|
|
// view keys
|
|
//
|
|
[self pollViewControls];
|
|
|
|
//if (![gameView allowingStringInput])
|
|
if (![universe displayCursor])
|
|
{
|
|
//
|
|
if (([gameView isDown:key_inject_fuel])&&(has_fuel_injection)&&(!hyperspeed_engaged)&&(status != STATUS_WITCHSPACE_COUNTDOWN))
|
|
{
|
|
if ((fuel > 0)&&(!afterburner_engaged))
|
|
{
|
|
[universe addMessage:[universe expandDescription:@"[fuel-inject-on]" forSystem:system_seed] forCount:1.5];
|
|
afterburner_engaged = YES;
|
|
if (!afterburnerSoundLooping)
|
|
[self loopAfterburnerSound];
|
|
}
|
|
else
|
|
{
|
|
if (fuel <= 0.0)
|
|
[universe addMessage:[universe expandDescription:@"[fuel-out]" forSystem:system_seed] forCount:1.5];
|
|
}
|
|
afterburner_engaged = (fuel > 0);
|
|
}
|
|
else
|
|
afterburner_engaged = NO;
|
|
|
|
if ((!afterburner_engaged)&&(afterburnerSoundLooping))
|
|
[self stopAfterburnerSound];
|
|
//
|
|
// if (([gameView isDown:key_increase_speed])&&(!hyperspeed_engaged)&&(!afterburner_engaged))
|
|
if (([gameView isDown:key_increase_speed])&&(flight_speed < max_flight_speed)&&(!afterburner_engaged))
|
|
{
|
|
if (flight_speed < max_flight_speed)
|
|
flight_speed += speed_delta * delta_t;
|
|
if (flight_speed > max_flight_speed)
|
|
flight_speed = max_flight_speed;
|
|
}
|
|
// if (([gameView isDown:key_decrease_speed])&&(!hyperspeed_engaged)&&(!afterburner_engaged))
|
|
// ** tgape ** - decrease obviously means no hyperspeed
|
|
if (([gameView isDown:key_decrease_speed])&&(!afterburner_engaged))
|
|
{
|
|
if (flight_speed > 0.0)
|
|
flight_speed -= speed_delta * delta_t;
|
|
if (flight_speed < 0.0)
|
|
flight_speed = 0.0;
|
|
// ** tgape ** - decrease obviously means no hyperspeed
|
|
hyperspeed_engaged = NO;
|
|
}
|
|
//
|
|
// hyperspeed controls
|
|
//
|
|
if ([gameView isDown:key_jumpdrive]) // 'j'
|
|
{
|
|
if (!jump_pressed)
|
|
{
|
|
if (!hyperspeed_engaged)
|
|
{
|
|
hyperspeed_locked = [self massLocked];
|
|
hyperspeed_engaged = !hyperspeed_locked;
|
|
if (hyperspeed_locked)
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if (![boopSound isPlaying])
|
|
[boopSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[jump-mass-locked]" forSystem:system_seed] forCount:1.5];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hyperspeed_engaged = NO;
|
|
}
|
|
}
|
|
jump_pressed = YES;
|
|
}
|
|
else
|
|
{
|
|
jump_pressed = NO;
|
|
}
|
|
//
|
|
// shoot 'a'
|
|
//
|
|
if ((([gameView isDown:key_fire_lasers])||((mouse_control_on)&&([gameView isDown:gvMouseLeftButton])))&&(shot_time > weapon_reload_time))
|
|
{
|
|
if ([self fireMainWeapon])
|
|
{
|
|
if (target_laser_hit != NO_TARGET)
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if (weaponHitSound)
|
|
{
|
|
if ([weaponHitSound isPlaying])
|
|
[weaponHitSound stop];
|
|
[weaponHitSound play];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (weaponSound)
|
|
{
|
|
if ([weaponSound isPlaying])
|
|
[weaponSound stop];
|
|
[weaponSound play];
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// shoot 'm' // launch missile
|
|
//
|
|
if ([gameView isDown:key_launch_missile])
|
|
{
|
|
// launch here
|
|
if (!fire_missile_pressed)
|
|
{
|
|
BOOL missile_noise = [[missile_entity[active_missile] roles] hasSuffix:@"MISSILE"];
|
|
if ([self fireMissile])
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if (missile_noise)
|
|
[missileSound play];
|
|
#endif
|
|
}
|
|
}
|
|
fire_missile_pressed = YES;
|
|
}
|
|
else
|
|
fire_missile_pressed = NO;
|
|
//
|
|
// shoot 'y' // next target
|
|
//
|
|
if ([gameView isDown:key_next_missile])
|
|
{
|
|
if ((!ident_engaged)&&(!next_target_pressed)&&([self has_extra_equipment:@"EQ_MULTI_TARGET"]))
|
|
{
|
|
[[universe gui] click];
|
|
[self select_next_missile];
|
|
}
|
|
next_target_pressed = YES;
|
|
}
|
|
else
|
|
next_target_pressed = NO;
|
|
//
|
|
// shoot 'r' // switch on ident system
|
|
//
|
|
if ([gameView isDown:key_ident_system])
|
|
{
|
|
// ident 'on' here
|
|
if (!ident_pressed)
|
|
{
|
|
missile_status = MISSILE_STATUS_ARMED;
|
|
primaryTarget = NO_TARGET;
|
|
ident_engaged = YES;
|
|
#ifdef HAVE_SOUND
|
|
if (![beepSound isPlaying])
|
|
[beepSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[ident-on]" forSystem:system_seed] forCount:2.0];
|
|
}
|
|
ident_pressed = YES;
|
|
}
|
|
else
|
|
ident_pressed = NO;
|
|
//
|
|
// shoot 't' // switch on missile targetting
|
|
//
|
|
if (([gameView isDown:key_target_missile])&&(missile_entity[active_missile]))
|
|
{
|
|
// targetting 'on' here
|
|
if (!target_missile_pressed)
|
|
{
|
|
missile_status = MISSILE_STATUS_ARMED;
|
|
if ((ident_engaged) && ([self getPrimaryTarget]))
|
|
{
|
|
if ([[missile_entity[active_missile] roles] hasSuffix:@"MISSILE"])
|
|
{
|
|
missile_status = MISSILE_STATUS_TARGET_LOCKED;
|
|
[missile_entity[active_missile] addTarget:[self getPrimaryTarget]];
|
|
[universe addMessage:[NSString stringWithFormat:[universe expandDescription:@"[missile-locked-onto-@]" forSystem:system_seed], [(ShipEntity *)[self getPrimaryTarget] name]] forCount:4.5];
|
|
}
|
|
#ifdef HAVE_SOUND
|
|
[beepSound play];
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
primaryTarget = NO_TARGET;
|
|
if ([[missile_entity[active_missile] roles] hasSuffix:@"MISSILE"])
|
|
{
|
|
if (missile_entity[active_missile])
|
|
[missile_entity[active_missile] removeTarget:nil];
|
|
[universe addMessage:[universe expandDescription:@"[missile-armed]" forSystem:system_seed] forCount:2.0];
|
|
}
|
|
#ifdef HAVE_SOUND
|
|
if (![beepSound isPlaying])
|
|
[beepSound play];
|
|
#endif
|
|
}
|
|
if ([[missile_entity[active_missile] roles] hasSuffix:@"MINE"])
|
|
{
|
|
[universe addMessage:[NSString stringWithFormat:[universe expandDescription:@"[mine-armed]" forSystem:system_seed], [(ShipEntity *)[self getPrimaryTarget] name]] forCount:4.5];
|
|
}
|
|
ident_engaged = NO;
|
|
}
|
|
target_missile_pressed = YES;
|
|
}
|
|
else
|
|
target_missile_pressed = NO;
|
|
//
|
|
// shoot 'u' // disarm missile targetting
|
|
//
|
|
if ([gameView isDown:key_untarget_missile])
|
|
{
|
|
if (!safety_pressed)
|
|
{
|
|
if (!ident_engaged)
|
|
{
|
|
// targetting 'off' here
|
|
missile_status = MISSILE_STATUS_SAFE;
|
|
primaryTarget = NO_TARGET;
|
|
[self safe_all_missiles];
|
|
#ifdef HAVE_SOUND
|
|
if (![boopSound isPlaying])
|
|
[boopSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[missile-safe]" forSystem:system_seed] forCount:2.0];
|
|
}
|
|
else
|
|
{
|
|
// targetting 'back on' here
|
|
primaryTarget = [missile_entity[active_missile] getPrimaryTargetID];
|
|
missile_status = (primaryTarget != NO_TARGET)? MISSILE_STATUS_TARGET_LOCKED : MISSILE_STATUS_SAFE;
|
|
#ifdef HAVE_SOUND
|
|
if (![boopSound isPlaying])
|
|
[boopSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[ident-off]" forSystem:system_seed] forCount:2.0];
|
|
}
|
|
ident_engaged = NO;
|
|
}
|
|
safety_pressed = YES;
|
|
}
|
|
else
|
|
safety_pressed = NO;
|
|
//
|
|
// shoot 'e' // ECM
|
|
//
|
|
if (([gameView isDown:key_ecm])&&(has_ecm))
|
|
{
|
|
if (!ecm_in_operation)
|
|
{
|
|
if ([self fireECM])
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
[ecmSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[ecm-on]" forSystem:system_seed] forCount:3.0];
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// shoot 'tab' // Energy bomb
|
|
//
|
|
if (([gameView isDown:key_energy_bomb])&&(has_energy_bomb))
|
|
{
|
|
// original energy bomb routine
|
|
[self fireEnergyBomb];
|
|
[self remove_extra_equipment:@"EQ_ENERGY_BOMB"];
|
|
}
|
|
//
|
|
// shoot 'escape' // Escape pod launch
|
|
//
|
|
if (([gameView isDown:key_launch_escapepod])&&(has_escape_pod)&&([universe station]))
|
|
{
|
|
found_target = [self launchEscapeCapsule];
|
|
}
|
|
//
|
|
// shoot 'd' // Dump Cargo
|
|
//
|
|
if (([gameView isDown:key_dump_cargo])&&([cargo count] > 0))
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if ([self dumpCargo] != CARGO_NOT_CARGO)
|
|
[beepSound play];
|
|
#else
|
|
[self dumpCargo];
|
|
#endif
|
|
}
|
|
//
|
|
// autopilot 'c'
|
|
//
|
|
if (([gameView isDown:key_autopilot])&&(has_docking_computer)&&(![beepSound isPlaying])) // look for the 'c' key
|
|
{
|
|
if ([self checkForAegis] == AEGIS_IN_DOCKING_RANGE)
|
|
{
|
|
primaryTarget = NO_TARGET;
|
|
targetStation = NO_TARGET;
|
|
autopilot_engaged = YES;
|
|
ident_engaged = NO;
|
|
[self safe_all_missiles];
|
|
// velocity = make_vector(v_forward.x * flight_speed, v_forward.y * flight_speed, v_forward.z * flight_speed);
|
|
velocity = make_vector( 0, 0, 0);
|
|
status = STATUS_AUTOPILOT_ENGAGED;
|
|
[shipAI setState:@"GLOBAL"]; // restart the AI
|
|
#ifdef HAVE_SOUND
|
|
[beepSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[autopilot-on]" forSystem:system_seed] forCount:4.5];
|
|
//
|
|
if (ootunes_on)
|
|
{
|
|
// ootunes - play docking music
|
|
[[universe gameController] playiTunesPlaylist:@"Oolite-Docking"];
|
|
}
|
|
else
|
|
{
|
|
if (docking_music_on)
|
|
{
|
|
#ifndef GNUSTEP
|
|
if (IsMovieDone ([dockingMusic QTMovie]))
|
|
GoToBeginningOfMovie ([dockingMusic QTMovie]);
|
|
StartMovie ([dockingMusic QTMovie]);
|
|
#else
|
|
[dockingMusic stop];
|
|
[dockingMusic goToBeginning];
|
|
[dockingMusic play];
|
|
#endif
|
|
}
|
|
}
|
|
//
|
|
if (afterburner_engaged)
|
|
{
|
|
afterburner_engaged = NO;
|
|
if (afterburnerSoundLooping)
|
|
[self stopAfterburnerSound];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if (![boopSound isPlaying])
|
|
[boopSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[autopilot-out-of-range]" forSystem:system_seed] forCount:4.5];
|
|
}
|
|
}
|
|
//
|
|
// autopilot 'C' - dock with target
|
|
//
|
|
if (([gameView isDown:key_autopilot_target])&&(has_docking_computer)&&(![beepSound isPlaying])) // look for the 'c' key
|
|
{
|
|
Entity* primeTarget = [self getPrimaryTarget];
|
|
if ((primeTarget)&&(primeTarget->isStation))
|
|
{
|
|
targetStation = primaryTarget;
|
|
primaryTarget = NO_TARGET;
|
|
autopilot_engaged = YES;
|
|
ident_engaged = NO;
|
|
[self safe_all_missiles];
|
|
// velocity = make_vector(v_forward.x * flight_speed, v_forward.y * flight_speed, v_forward.z * flight_speed);
|
|
velocity = make_vector( 0, 0, 0);
|
|
status = STATUS_AUTOPILOT_ENGAGED;
|
|
[shipAI setState:@"GLOBAL"]; // restart the AI
|
|
#ifdef HAVE_SOUND
|
|
[beepSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[autopilot-on]" forSystem:system_seed] forCount:4.5];
|
|
//
|
|
if (ootunes_on)
|
|
{
|
|
// ootunes - play docking music
|
|
[[universe gameController] playiTunesPlaylist:@"Oolite-Docking"];
|
|
}
|
|
else
|
|
{
|
|
if (docking_music_on)
|
|
{
|
|
#ifndef GNUSTEP
|
|
if (IsMovieDone ([dockingMusic QTMovie]))
|
|
GoToBeginningOfMovie ([dockingMusic QTMovie]);
|
|
StartMovie ([dockingMusic QTMovie]);
|
|
#else
|
|
[dockingMusic stop];
|
|
[dockingMusic goToBeginning];
|
|
[dockingMusic play];
|
|
#endif
|
|
}
|
|
}
|
|
//
|
|
if (afterburner_engaged)
|
|
{
|
|
afterburner_engaged = NO;
|
|
if (afterburnerSoundLooping)
|
|
[self stopAfterburnerSound];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if (![boopSound isPlaying])
|
|
[boopSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"Target is not capable of autopilot-docking" forSystem:system_seed] forCount:4.5];
|
|
}
|
|
}
|
|
//
|
|
// autopilot 'D'
|
|
//
|
|
if (([gameView isDown:key_autodock])&&(has_docking_computer)&&(![beepSound isPlaying])) // look for the 'D' key
|
|
{
|
|
if ([self checkForAegis] == AEGIS_IN_DOCKING_RANGE)
|
|
{
|
|
StationEntity *the_station = [universe station];
|
|
if (the_station)
|
|
{
|
|
if (legal_status > 50)
|
|
{
|
|
status = STATUS_AUTOPILOT_ENGAGED;
|
|
[self interpretAIMessage:@"DOCKING_REFUSED"];
|
|
}
|
|
else
|
|
{
|
|
ship_clock_adjust = 300.0; // 5 minutes penalty to enter dock
|
|
ident_engaged = NO;
|
|
[self safe_all_missiles];
|
|
[universe setViewDirection:VIEW_FORWARD];
|
|
[self enterDock:the_station];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if (![boopSound isPlaying])
|
|
[boopSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[autopilot-out-of-range]" forSystem:system_seed] forCount:4.5];
|
|
}
|
|
}
|
|
//
|
|
// hyperspace 'h'
|
|
//
|
|
if ([gameView isDown:key_hyperspace]) // look for the 'h' key
|
|
{
|
|
float dx = target_system_seed.d - galaxy_coordinates.x;
|
|
float dy = target_system_seed.b - galaxy_coordinates.y;
|
|
double distance = distanceBetweenPlanetPositions(target_system_seed.d,target_system_seed.b,galaxy_coordinates.x,galaxy_coordinates.y);
|
|
BOOL jumpOK = YES;
|
|
|
|
if ((dx == 0)&&(dy == 0))
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
[boopSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[witch-no-target]" forSystem:system_seed] forCount:3.0];
|
|
jumpOK = NO;
|
|
}
|
|
|
|
if (10.0 * distance > fuel)
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
[boopSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[witch-no-fuel]" forSystem:system_seed] forCount:3.0];
|
|
jumpOK = NO;
|
|
}
|
|
|
|
if (status == STATUS_WITCHSPACE_COUNTDOWN)
|
|
jumpOK = NO;
|
|
|
|
if (jumpOK)
|
|
{
|
|
galactic_witchjump = NO;
|
|
witchspaceCountdown = 15.0;
|
|
status = STATUS_WITCHSPACE_COUNTDOWN;
|
|
#ifdef HAVE_SOUND
|
|
[beepSound play];
|
|
#endif
|
|
// say it!
|
|
[universe addMessage:[NSString stringWithFormat:[universe expandDescription:@"[witch-to-@-in-f-seconds]" forSystem:system_seed], [universe getSystemName:target_system_seed], witchspaceCountdown] forCount:1.0];
|
|
}
|
|
}
|
|
//
|
|
// emergency hyperspace 'H'
|
|
//
|
|
// if ([gameView isDown:key_emergency_hyperdrive]) // look for the 'h' key
|
|
// {
|
|
// BOOL jumpOK = [self has_extra_equipment:@"EQ_EMERGENCY_HYPERDRIVE"];
|
|
//
|
|
// if (status == STATUS_WITCHSPACE_COUNTDOWN)
|
|
// jumpOK = NO;
|
|
//
|
|
// if (jumpOK)
|
|
// {
|
|
// galactic_witchjump = NO;
|
|
// [universe addMessage:@"Emergency witch-jump!" forCount:2.0];
|
|
// [self enterWitchspaceWithEmergencyDrive];
|
|
// }
|
|
// }
|
|
//
|
|
// Galactic hyperspace 'g'
|
|
//
|
|
if (([gameView isDown:key_galactic_hyperspace])&&(has_galactic_hyperdrive))// look for the 'g' key
|
|
{
|
|
BOOL jumpOK = YES;
|
|
|
|
if (status == STATUS_WITCHSPACE_COUNTDOWN)
|
|
jumpOK = NO;
|
|
|
|
if (jumpOK)
|
|
{
|
|
galactic_witchjump = YES;
|
|
witchspaceCountdown = 15.0;
|
|
status = STATUS_WITCHSPACE_COUNTDOWN;
|
|
#ifdef HAVE_SOUND
|
|
[beepSound play];
|
|
#endif
|
|
// say it!
|
|
[universe addMessage:[NSString stringWithFormat:[universe expandDescription:@"[witch-galactic-in-f-seconds]" forSystem:system_seed], witchspaceCountdown] forCount:1.0];
|
|
}
|
|
}
|
|
//
|
|
// shoot '0' // Cloaking Device
|
|
//
|
|
if ([gameView isDown:key_cloaking_device] && has_cloaking_device)
|
|
{
|
|
if (!cloak_pressed)
|
|
{
|
|
if (!cloaking_device_active)
|
|
{
|
|
if ([self activateCloakingDevice])
|
|
[universe addMessage:[universe expandDescription:@"[cloak-on]" forSystem:system_seed] forCount:2];
|
|
else
|
|
[universe addMessage:[universe expandDescription:@"[cloak-low-juice]" forSystem:system_seed] forCount:3];
|
|
}
|
|
else
|
|
{
|
|
[self deactivateCloakingDevice];
|
|
[universe addMessage:[universe expandDescription:@"[cloak-off]" forSystem:system_seed] forCount:2];
|
|
}
|
|
//
|
|
#ifdef HAVE_SOUND
|
|
if (cloaking_device_active)
|
|
[beepSound play];
|
|
else
|
|
[boopSound play];
|
|
#endif
|
|
}
|
|
cloak_pressed = YES;
|
|
}
|
|
else
|
|
cloak_pressed = NO;
|
|
|
|
}
|
|
|
|
// // test novas
|
|
// if ([gameView isDown:48]) // '0'
|
|
// {
|
|
// if (![[universe sun] willGoNova])
|
|
// {
|
|
// [[universe sun] setGoingNova:YES inTime:10.0];
|
|
// [self warnAboutHostiles];
|
|
// [universe addMessage:@"Sun going nova in 10 s." forCount:6];
|
|
// NSLog(@"DEBUG NOVA activated!");
|
|
// }
|
|
// else
|
|
// {
|
|
// if (fuel_leak_rate <= 0.0)
|
|
// {
|
|
// fuel_leak_rate = 25.0;
|
|
// [universe addMessage:@"Danger! Fuel leak!" forCount:6];
|
|
// NSLog(@"DEBUG FUEL LEAK activated!");
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
//
|
|
// text displays
|
|
//
|
|
[self pollGuiScreenControls];
|
|
}
|
|
//
|
|
// Pause game 'p'
|
|
//
|
|
if ([gameView isDown:key_pausebutton])// look for the 'p' key
|
|
{
|
|
if (!pause_pressed)
|
|
{
|
|
if (paused)
|
|
{
|
|
[universe clearPreviousMessage];
|
|
[[gameView gameController] unpause_game];
|
|
}
|
|
else
|
|
{
|
|
[universe addMessage:[universe expandDescription:@"[game-paused]" forSystem:system_seed] forCount:1.0];
|
|
[[gameView gameController] pause_game];
|
|
}
|
|
}
|
|
pause_pressed = YES;
|
|
}
|
|
else
|
|
{
|
|
pause_pressed = NO;
|
|
}
|
|
//
|
|
//
|
|
//
|
|
}
|
|
|
|
static BOOL f_key_pressed;
|
|
static BOOL m_key_pressed;
|
|
static BOOL taking_snapshot;
|
|
- (void) pollApplicationControls
|
|
{
|
|
// does fullscreen / quit / snapshot
|
|
//
|
|
MyOpenGLView *gameView = (MyOpenGLView *)[universe gameView];
|
|
//
|
|
// command-key controls
|
|
//
|
|
if (([gameView isCommandDown])&&([[gameView gameController] inFullScreenMode]))
|
|
{
|
|
if (([gameView isCommandDown])&&([gameView isDown:102])) // command f
|
|
{
|
|
[[gameView gameController] exitFullScreenMode];
|
|
if (mouse_control_on)
|
|
[universe addMessage:[universe expandDescription:@"[mouse-off]" forSystem:system_seed] forCount:3.0];
|
|
mouse_control_on = NO;
|
|
}
|
|
//
|
|
if (([gameView isCommandDown])&&([gameView isDown:113])) // command q
|
|
{
|
|
[[gameView gameController] pauseFullScreenModeToPerform:@selector(exitApp) onTarget:[gameView gameController]];
|
|
}
|
|
}
|
|
//
|
|
// snapshot
|
|
//
|
|
if ([gameView isDown:key_snapshot]) // '*' key
|
|
{
|
|
if (!taking_snapshot)
|
|
{
|
|
taking_snapshot = YES;
|
|
[gameView snapShot];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
taking_snapshot = NO;
|
|
}
|
|
//
|
|
// FPS display
|
|
//
|
|
if ([gameView isDown:key_show_fps]) // 'F' key
|
|
{
|
|
if (!f_key_pressed)
|
|
[universe setDisplayFPS:![universe displayFPS]];
|
|
f_key_pressed = YES;
|
|
}
|
|
else
|
|
{
|
|
f_key_pressed = NO;
|
|
}
|
|
//
|
|
// Mouse control
|
|
//
|
|
if ([[gameView gameController] inFullScreenMode])
|
|
{
|
|
if ([gameView isDown:key_mouse_control]) // 'M' key
|
|
{
|
|
if (!m_key_pressed)
|
|
{
|
|
mouse_control_on = !mouse_control_on;
|
|
if (mouse_control_on)
|
|
[universe addMessage:[universe expandDescription:@"[mouse-on]" forSystem:system_seed] forCount:3.0];
|
|
else
|
|
[universe addMessage:[universe expandDescription:@"[mouse-off]" forSystem:system_seed] forCount:3.0];
|
|
}
|
|
m_key_pressed = YES;
|
|
}
|
|
else
|
|
{
|
|
m_key_pressed = NO;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) pollFlightArrowKeyControls:(double) delta_t
|
|
{
|
|
MyOpenGLView *gameView = (MyOpenGLView *)[universe gameView];
|
|
NSPoint virtualStick =[gameView virtualJoystickPosition];
|
|
double sensitivity = 2.0;
|
|
virtualStick.x *= sensitivity;
|
|
virtualStick.y *= sensitivity;
|
|
double roll_dampner = ROLL_DAMPING_FACTOR * delta_t;
|
|
double pitch_dampner = PITCH_DAMPING_FACTOR * delta_t;
|
|
|
|
rolling = NO;
|
|
if (!mouse_control_on)
|
|
{
|
|
if ([gameView isDown:key_roll_left])
|
|
{
|
|
if (flight_roll > 0.0) flight_roll = 0.0;
|
|
[self decrease_flight_roll:delta_t*roll_delta];
|
|
rolling = YES;
|
|
}
|
|
if ([gameView isDown:key_roll_right])
|
|
{
|
|
if (flight_roll < 0.0) flight_roll = 0.0;
|
|
[self increase_flight_roll:delta_t*roll_delta];
|
|
rolling = YES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
double stick_roll = max_flight_roll * virtualStick.x;
|
|
if (flight_roll < stick_roll)
|
|
{
|
|
[self increase_flight_roll:delta_t*roll_delta];
|
|
if (flight_roll > stick_roll)
|
|
flight_roll = stick_roll;
|
|
}
|
|
if (flight_roll > stick_roll)
|
|
{
|
|
[self decrease_flight_roll:delta_t*roll_delta];
|
|
if (flight_roll < stick_roll)
|
|
flight_roll = stick_roll;
|
|
}
|
|
rolling = (abs(virtualStick.x) > .10);
|
|
}
|
|
if (!rolling)
|
|
{
|
|
if (flight_roll > 0.0)
|
|
{
|
|
if (flight_roll > roll_dampner) [self decrease_flight_roll:roll_dampner];
|
|
else flight_roll = 0.0;
|
|
}
|
|
if (flight_roll < 0.0)
|
|
{
|
|
if (flight_roll < -roll_dampner) [self increase_flight_roll:roll_dampner];
|
|
else flight_roll = 0.0;
|
|
}
|
|
}
|
|
|
|
pitching = NO;
|
|
if (!mouse_control_on)
|
|
{
|
|
if ([gameView isDown:key_pitch_back])
|
|
{
|
|
if (flight_pitch < 0.0) flight_pitch = 0.0;
|
|
[self increase_flight_pitch:delta_t*pitch_delta];
|
|
pitching = YES;
|
|
}
|
|
if ([gameView isDown:key_pitch_forward])
|
|
{
|
|
if (flight_pitch > 0.0) flight_pitch = 0.0;
|
|
[self decrease_flight_pitch:delta_t*pitch_delta];
|
|
pitching = YES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
double stick_pitch = max_flight_pitch * virtualStick.y;
|
|
if (flight_pitch < stick_pitch)
|
|
{
|
|
[self increase_flight_pitch:delta_t*roll_delta];
|
|
if (flight_pitch > stick_pitch)
|
|
flight_pitch = stick_pitch;
|
|
}
|
|
if (flight_pitch > stick_pitch)
|
|
{
|
|
[self decrease_flight_pitch:delta_t*roll_delta];
|
|
if (flight_pitch < stick_pitch)
|
|
flight_pitch = stick_pitch;
|
|
}
|
|
pitching = (abs(virtualStick.x) > .10);
|
|
}
|
|
if (!pitching)
|
|
{
|
|
if (flight_pitch > 0.0)
|
|
{
|
|
if (flight_pitch > pitch_dampner) [self decrease_flight_pitch:pitch_dampner];
|
|
else flight_pitch = 0.0;
|
|
}
|
|
if (flight_pitch < 0.0)
|
|
{
|
|
if (flight_pitch < -pitch_dampner) [self increase_flight_pitch:pitch_dampner];
|
|
else flight_pitch = 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***JESTER_START*** 11/08/04
|
|
//Utility function
|
|
#ifndef GNUSTEP
|
|
static NSString* GenerateDisplayString(int inModeWidth, int inModeHeight, int inModeRefresh);
|
|
#endif
|
|
// ***JESTER_END*** 11/08/04
|
|
|
|
static BOOL pling_pressed;
|
|
static BOOL cursor_moving;
|
|
static BOOL disc_operation_in_progress;
|
|
#ifndef GNUSTEP
|
|
static BOOL switching_resolution;
|
|
#endif
|
|
static BOOL wait_for_key_up;
|
|
static int searchStringLength;
|
|
static double timeLastKeyPress;
|
|
static BOOL upDownKeyPressed;
|
|
static int oldSelection;
|
|
static BOOL selectPressed;
|
|
static BOOL queryPressed;
|
|
- (void) pollGuiArrowKeyControls:(double) delta_t
|
|
{
|
|
MyOpenGLView *gameView = (MyOpenGLView *)[universe gameView];
|
|
BOOL moving = NO;
|
|
double cursor_speed = 10.0;
|
|
GuiDisplayGen* gui = [universe gui];
|
|
|
|
[gameView allowStringInput:(gui_screen == GUI_SCREEN_LONG_RANGE_CHART)];
|
|
|
|
switch (gui_screen)
|
|
{
|
|
case GUI_SCREEN_LONG_RANGE_CHART :
|
|
if ([gameView isDown:key_map_dump]) // '!' key
|
|
{
|
|
if (!pling_pressed)
|
|
[self starChartDump];
|
|
pling_pressed = YES;
|
|
}
|
|
else
|
|
{
|
|
pling_pressed = NO;
|
|
}
|
|
if ([[gameView typedString] length])
|
|
{
|
|
planetSearchString = [gameView typedString];
|
|
//NSLog(@"searching for %@", planetSearchString);
|
|
NSPoint search_coords = [universe findSystemCoordinatesWithPrefix:planetSearchString withGalaxySeed:galaxy_seed];
|
|
if ((search_coords.x >= 0.0)&&(search_coords.y >= 0.0))
|
|
{
|
|
//NSLog(@"found somewhere");
|
|
moving = ((cursor_coordinates.x != search_coords.x)||(cursor_coordinates.y != search_coords.y));
|
|
//searchStringLength = [[gameView typedString] length];
|
|
cursor_coordinates = search_coords;
|
|
}
|
|
else
|
|
{
|
|
[gameView resetTypedString];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
planetSearchString = nil;
|
|
}
|
|
//
|
|
if ((status == STATUS_DOCKED)&&([gameView isDown:63])) // '?' toggle between map and contract screen
|
|
{
|
|
if (!queryPressed)
|
|
{
|
|
[self setGuiToContractsScreen];
|
|
if ((oldSelection >= [gui selectableRange].location)&&(oldSelection < [gui selectableRange].location + [gui selectableRange].length))
|
|
[gui setSelectedRow:oldSelection];
|
|
[self setGuiToContractsScreen];
|
|
[universe setDisplayCursor:NO];
|
|
}
|
|
queryPressed = YES;
|
|
}
|
|
else
|
|
queryPressed = NO;
|
|
//
|
|
moving |= (searchStringLength != [[gameView typedString] length]);
|
|
searchStringLength = [[gameView typedString] length];
|
|
//
|
|
case GUI_SCREEN_SHORT_RANGE_CHART :
|
|
if (status != STATUS_WITCHSPACE_COUNTDOWN)
|
|
{
|
|
if ([gameView isDown:gvMouseLeftButton])
|
|
{
|
|
NSPoint maus = [gameView virtualJoystickPosition];
|
|
if (gui_screen == GUI_SCREEN_SHORT_RANGE_CHART)
|
|
{
|
|
double vadjust = 51;
|
|
double hscale = 4.0 * MAIN_GUI_PIXEL_WIDTH / 256.0;
|
|
double vscale = 4.0 * MAIN_GUI_PIXEL_HEIGHT / 512.0;
|
|
cursor_coordinates.x = galaxy_coordinates.x + (maus.x * MAIN_GUI_PIXEL_WIDTH) / hscale;
|
|
cursor_coordinates.y = galaxy_coordinates.y + (maus.y * MAIN_GUI_PIXEL_HEIGHT + vadjust) / vscale;
|
|
//NSLog(@"DEBUG mouse (%.3f,%.3f), coordinates (%.3f,%.3f) vadjust %.1f", maus.x, maus.y, cursor_coordinates.x, cursor_coordinates.y, vadjust);
|
|
}
|
|
if (gui_screen == GUI_SCREEN_LONG_RANGE_CHART)
|
|
{
|
|
double vadjust = 211;
|
|
double hadjust = MAIN_GUI_PIXEL_WIDTH / 2.0;
|
|
double hscale = MAIN_GUI_PIXEL_WIDTH / 256.0;
|
|
double vscale = MAIN_GUI_PIXEL_HEIGHT / 512.0;
|
|
cursor_coordinates.x = (maus.x * MAIN_GUI_PIXEL_WIDTH + hadjust)/ hscale;
|
|
cursor_coordinates.y = (maus.y * MAIN_GUI_PIXEL_HEIGHT + vadjust) / vscale;
|
|
//NSLog(@"DEBUG mouse (%.3f,%.3f), coordinates (%.3f,%.3f) vadjust %.1f", maus.x, maus.y, cursor_coordinates.x, cursor_coordinates.y, vadjust);
|
|
}
|
|
[gameView resetTypedString];
|
|
moving = YES;
|
|
}
|
|
if ([gameView isDown:key_map_home])
|
|
{
|
|
[gameView resetTypedString];
|
|
cursor_coordinates = galaxy_coordinates;
|
|
moving = YES;
|
|
}
|
|
if ([gameView isDown:gvArrowKeyLeft])
|
|
{
|
|
[gameView resetTypedString];
|
|
cursor_coordinates.x -= cursor_speed*delta_t;
|
|
if (cursor_coordinates.x < 0.0) cursor_coordinates.x = 0.0;
|
|
moving = YES;
|
|
}
|
|
if ([gameView isDown:gvArrowKeyRight])
|
|
{
|
|
[gameView resetTypedString];
|
|
cursor_coordinates.x += cursor_speed*delta_t;
|
|
if (cursor_coordinates.x > 256.0) cursor_coordinates.x = 256.0;
|
|
moving = YES;
|
|
}
|
|
if ([gameView isDown:gvArrowKeyDown])
|
|
{
|
|
[gameView resetTypedString];
|
|
cursor_coordinates.y += cursor_speed*delta_t*2.0;
|
|
if (cursor_coordinates.y > 256.0) cursor_coordinates.y = 256.0;
|
|
moving = YES;
|
|
}
|
|
if ([gameView isDown:gvArrowKeyUp])
|
|
{
|
|
[gameView resetTypedString];
|
|
cursor_coordinates.y -= cursor_speed*delta_t*2.0;
|
|
if (cursor_coordinates.y < 0.0) cursor_coordinates.y = 0.0;
|
|
moving = YES;
|
|
}
|
|
if ((cursor_moving)&&(!moving))
|
|
{
|
|
target_system_seed = [universe findSystemAtCoords:cursor_coordinates withGalaxySeed:galaxy_seed];
|
|
cursor_coordinates.x = target_system_seed.d;
|
|
cursor_coordinates.y = target_system_seed.b;
|
|
if (gui_screen == GUI_SCREEN_LONG_RANGE_CHART) [self setGuiToLongRangeChartScreen];
|
|
if (gui_screen == GUI_SCREEN_SHORT_RANGE_CHART) [self setGuiToShortRangeChartScreen];
|
|
}
|
|
cursor_moving = moving;
|
|
if ((cursor_moving)&&(gui_screen == GUI_SCREEN_LONG_RANGE_CHART)) [self setGuiToLongRangeChartScreen]; // update graphics
|
|
if ((cursor_moving)&&(gui_screen == GUI_SCREEN_SHORT_RANGE_CHART)) [self setGuiToShortRangeChartScreen]; // update graphics
|
|
}
|
|
break;
|
|
|
|
case GUI_SCREEN_OPTIONS :
|
|
{
|
|
int quicksave_row = GUI_ROW_OPTIONS_QUICKSAVE;
|
|
int save_row = GUI_ROW_OPTIONS_SAVE;
|
|
int load_row = GUI_ROW_OPTIONS_LOAD;
|
|
int begin_new_row = GUI_ROW_OPTIONS_BEGIN_NEW;
|
|
int options_row = GUI_ROW_OPTIONS_OPTIONS;
|
|
int ootunes_row = GUI_ROW_OPTIONS_OOTUNES;
|
|
int strict_row = GUI_ROW_OPTIONS_STRICT;
|
|
int detail_row = GUI_ROW_OPTIONS_DETAIL;
|
|
#ifdef GNUSTEP
|
|
// quit only appears in GNUstep as users aren't
|
|
// used to Cmd-Q equivs.
|
|
int quit_row = GUI_ROW_OPTIONS_QUIT;
|
|
#else
|
|
// Macintosh only
|
|
int display_row = GUI_ROW_OPTIONS_DISPLAY;
|
|
int speech_row = GUI_ROW_OPTIONS_SPEECH;
|
|
NSArray *modes = [controller displayModes];
|
|
GameController *controller = [universe gameController];
|
|
#endif
|
|
|
|
if ([gameView isDown:gvArrowKeyDown])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
|
|
if ([gui setSelectedRow:[gui selectedRow] + 1])
|
|
{
|
|
if ([gui selectedRow] == options_row)
|
|
[gui setSelectedRow:[gui selectedRow] + 1];
|
|
[gui click];
|
|
[universe guiUpdated];
|
|
}
|
|
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
if ([gameView isDown:gvArrowKeyUp])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([gui setSelectedRow:[gui selectedRow] - 1])
|
|
{
|
|
if ([gui selectedRow] == options_row)
|
|
[gui setSelectedRow:[gui selectedRow] - 1];
|
|
[gui click];
|
|
[universe guiUpdated];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
upDownKeyPressed = (([gameView isDown:gvArrowKeyUp])||([gameView isDown:gvArrowKeyDown]));
|
|
|
|
if ([gameView isDown:13]) // 'enter'
|
|
{
|
|
if (([gui selectedRow] == quicksave_row)&&(!disc_operation_in_progress))
|
|
{
|
|
NS_DURING
|
|
disc_operation_in_progress = YES;
|
|
[self quicksavePlayer];
|
|
NS_HANDLER
|
|
NSLog(@"\n\n***** Handling localException: %@ : %@ *****\n\n",[localException name], [localException reason]);
|
|
if ([[localException name] isEqual:@"GameNotSavedException"]) // try saving game instead
|
|
{
|
|
NSLog(@"\n\n***** Trying a normal save instead *****\n\n");
|
|
if ([[universe gameController] inFullScreenMode])
|
|
[[universe gameController] pauseFullScreenModeToPerform:@selector(savePlayer) onTarget:self];
|
|
else
|
|
[self savePlayer];
|
|
}
|
|
else
|
|
{
|
|
[localException raise];
|
|
}
|
|
NS_ENDHANDLER
|
|
}
|
|
if (([gui selectedRow] == save_row)&&(!disc_operation_in_progress))
|
|
{
|
|
disc_operation_in_progress = YES;
|
|
if ([[universe gameController] inFullScreenMode])
|
|
[[universe gameController] pauseFullScreenModeToPerform:@selector(savePlayer) onTarget:self];
|
|
else
|
|
[self savePlayer];
|
|
}
|
|
if (([gui selectedRow] == load_row)&&(!disc_operation_in_progress))
|
|
{
|
|
disc_operation_in_progress = YES;
|
|
if ([[universe gameController] inFullScreenMode])
|
|
[[universe gameController] pauseFullScreenModeToPerform:@selector(loadPlayer) onTarget:self];
|
|
else
|
|
[self loadPlayer];
|
|
}
|
|
if (([gui selectedRow] == begin_new_row)&&(!disc_operation_in_progress))
|
|
{
|
|
disc_operation_in_progress = YES;
|
|
[universe reinit];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
disc_operation_in_progress = NO;
|
|
}
|
|
|
|
#ifndef GNUSTEP
|
|
if (([gui selectedRow] == display_row)&&(([gameView isDown:gvArrowKeyRight])||([gameView isDown:gvArrowKeyLeft]))&&(!switching_resolution))
|
|
{
|
|
int direction = ([gameView isDown:gvArrowKeyRight]) ? 1 : -1;
|
|
int displayModeIndex = [controller indexOfCurrentDisplayMode];
|
|
if (displayModeIndex == NSNotFound)
|
|
{
|
|
NSLog(@"***** couldn't find current display mode switching to basic 640x480");
|
|
displayModeIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
displayModeIndex = displayModeIndex + direction;
|
|
if (displayModeIndex < 0)
|
|
displayModeIndex = [modes count] - 1;
|
|
if (displayModeIndex >= [modes count])
|
|
displayModeIndex = 0;
|
|
}
|
|
NSDictionary *mode = [modes objectAtIndex:displayModeIndex];
|
|
int modeWidth = [[mode objectForKey: (NSString *)kCGDisplayWidth] intValue];
|
|
int modeHeight = [[mode objectForKey: (NSString *)kCGDisplayHeight] intValue];
|
|
int modeRefresh = [[mode objectForKey: (NSString *)kCGDisplayRefreshRate] intValue];
|
|
[controller setDisplayWidth:modeWidth Height:modeHeight Refresh:modeRefresh];
|
|
// ****JESTER_START*** 11/08/04
|
|
//NSString *displayModeString = [NSString stringWithFormat:@" Fullscreen: %d x %d at %d Hz ", modeWidth, modeHeight, modeRefresh];
|
|
NSString *displayModeString = GenerateDisplayString(modeWidth, modeHeight, modeRefresh);
|
|
// ****JESTER_END*** 11/08/04
|
|
[gui click];
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
int display_row = GUI_ROW_OPTIONS_DISPLAY;
|
|
[gui setText:displayModeString forRow:display_row align:GUI_ALIGN_CENTER];
|
|
[universe guiUpdated];
|
|
}
|
|
switching_resolution = YES;
|
|
}
|
|
if ((![gameView isDown:gvArrowKeyRight])&&(![gameView isDown:gvArrowKeyLeft])&&(![gameView isDown:13]))
|
|
switching_resolution = NO;
|
|
|
|
if (([gui selectedRow] == speech_row)&&(([gameView isDown:gvArrowKeyRight])||([gameView isDown:gvArrowKeyLeft])))
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
if ([gameView isDown:gvArrowKeyRight] != speech_on)
|
|
[gui click];
|
|
speech_on = [gameView isDown:gvArrowKeyRight];
|
|
if (speech_on)
|
|
[gui setText:@" Spoken messages: ON " forRow:speech_row align:GUI_ALIGN_CENTER];
|
|
else
|
|
[gui setText:@" Spoken messages: OFF " forRow:speech_row align:GUI_ALIGN_CENTER];
|
|
[universe guiUpdated];
|
|
}
|
|
#endif
|
|
|
|
if (([gui selectedRow] == ootunes_row)&&(([gameView isDown:gvArrowKeyRight])||([gameView isDown:gvArrowKeyLeft])))
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
if ([gameView isDown:gvArrowKeyRight] != ootunes_on)
|
|
[gui click];
|
|
ootunes_on = [gameView isDown:gvArrowKeyRight];
|
|
#ifdef GNUSTEP
|
|
if (ootunes_on)
|
|
[gui setText:@" xine integration: ON " forRow:ootunes_row align:GUI_ALIGN_CENTER];
|
|
else
|
|
[gui setText:@" xine integration: OFF " forRow:ootunes_row align:GUI_ALIGN_CENTER];
|
|
#else
|
|
if (ootunes_on)
|
|
[gui setText:@" iTunes integration: ON " forRow:ootunes_row align:GUI_ALIGN_CENTER];
|
|
else
|
|
[gui setText:@" iTunes integration: OFF " forRow:ootunes_row align:GUI_ALIGN_CENTER];
|
|
#endif
|
|
[universe guiUpdated];
|
|
}
|
|
|
|
if (([gui selectedRow] == detail_row)&&(([gameView isDown:gvArrowKeyRight])||([gameView isDown:gvArrowKeyLeft])))
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
if ([gameView isDown:gvArrowKeyRight] != [universe reducedDetail])
|
|
[gui click];
|
|
[universe setReducedDetail:[gameView isDown:gvArrowKeyRight]];
|
|
if ([universe reducedDetail])
|
|
[gui setText:@" Reduced detail: ON " forRow:detail_row align:GUI_ALIGN_CENTER];
|
|
else
|
|
[gui setText:@" Reduced detail: OFF " forRow:detail_row align:GUI_ALIGN_CENTER];
|
|
[universe guiUpdated];
|
|
}
|
|
|
|
#ifdef GNUSTEP
|
|
// GNUstep only menu quit item
|
|
if (([gui selectedRow] == quit_row) && [gameView isDown:13])
|
|
{
|
|
[[gameView gameController] exitApp];
|
|
}
|
|
#endif
|
|
// TODO: Investigate why this has to be handled last (if the
|
|
// quit item and this are swapped, the game crashes if
|
|
// strict mode is selected with SIGSEGV in the ObjC runtime
|
|
// system. The stack trace shows it crashes when it hits
|
|
// the if statement, trying to send the message to one of
|
|
// the things contained.
|
|
if (([gui selectedRow] == strict_row)&&[gameView isDown:13])
|
|
{
|
|
[universe setStrict:![universe strict]];
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case GUI_SCREEN_EQUIP_SHIP :
|
|
{
|
|
if ([gameView isDown:gvArrowKeyDown])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([gui setSelectedRow:[gui selectedRow] + 1])
|
|
{
|
|
[gui click];
|
|
[self showInformationForSelectedUpgrade];
|
|
[universe guiUpdated];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
if ([gameView isDown:gvArrowKeyUp])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([gui setSelectedRow:[gui selectedRow] - 1])
|
|
{
|
|
[gui click];
|
|
[self showInformationForSelectedUpgrade];
|
|
[universe guiUpdated];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
if ([gameView isDown:gvArrowKeyLeft])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([[gui keyForRow:GUI_ROW_EQUIPMENT_START] hasPrefix:@"More:"])
|
|
{
|
|
[gui click];
|
|
[gui setSelectedRow:GUI_ROW_EQUIPMENT_START];
|
|
[self buySelectedItem];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
if ([gameView isDown:gvArrowKeyRight])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([[gui keyForRow:GUI_ROW_EQUIPMENT_START + GUI_MAX_ROWS_EQUIPMENT - 1] hasPrefix:@"More:"])
|
|
{
|
|
[gui click];
|
|
[gui setSelectedRow:GUI_ROW_EQUIPMENT_START + GUI_MAX_ROWS_EQUIPMENT - 1];
|
|
[self buySelectedItem];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
upDownKeyPressed = (([gameView isDown:gvArrowKeyUp])||([gameView isDown:gvArrowKeyDown])||([gameView isDown:gvArrowKeyRight])||([gameView isDown:gvArrowKeyLeft]));
|
|
|
|
if ([gameView isDown:13]) // 'enter'
|
|
{
|
|
if ((!selectPressed)&&([gui selectedRow] > -1))
|
|
{
|
|
[self buySelectedItem];
|
|
selectPressed = YES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
selectPressed = NO;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case GUI_SCREEN_MARKET :
|
|
if (status == STATUS_DOCKED)
|
|
{
|
|
if ([gameView isDown:gvArrowKeyDown])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([gui setSelectedRow:[gui selectedRow] + 1])
|
|
{
|
|
[gui click];
|
|
[universe guiUpdated];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
if ([gameView isDown:gvArrowKeyUp])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([gui setSelectedRow:[gui selectedRow] - 1])
|
|
{
|
|
[gui click];
|
|
[universe guiUpdated];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
upDownKeyPressed = (([gameView isDown:gvArrowKeyUp])||([gameView isDown:gvArrowKeyDown]));
|
|
|
|
if (([gameView isDown:gvArrowKeyRight])||([gameView isDown:gvArrowKeyLeft])||([gameView isDown:13]))
|
|
{
|
|
if ([gameView isDown:gvArrowKeyRight]) // -->
|
|
{
|
|
if (!wait_for_key_up)
|
|
{
|
|
int item = [(NSString *)[gui selectedRowKey] intValue];
|
|
//NSLog(@"Try Buying Commodity %d",item);
|
|
if ([self tryBuyingCommodity:item])
|
|
[self setGuiToMarketScreen];
|
|
#ifdef HAVE_SOUND
|
|
else
|
|
[boopSound play];
|
|
#endif
|
|
wait_for_key_up = YES;
|
|
}
|
|
}
|
|
if ([gameView isDown:gvArrowKeyLeft]) // <--
|
|
{
|
|
if (!wait_for_key_up)
|
|
{
|
|
int item = [(NSString *)[gui selectedRowKey] intValue];
|
|
//NSLog(@"Try Selling Commodity %d",item);
|
|
if ([self trySellingCommodity:item])
|
|
[self setGuiToMarketScreen];
|
|
#ifdef HAVE_SOUND
|
|
else
|
|
[boopSound play];
|
|
#endif
|
|
wait_for_key_up = YES;
|
|
}
|
|
}
|
|
if ([gameView isDown:13]) // 'enter'
|
|
{
|
|
if (!wait_for_key_up)
|
|
{
|
|
int item = [(NSString *)[gui selectedRowKey] intValue];
|
|
int yours = [(NSNumber *)[(NSArray *)[shipCommodityData objectAtIndex:item] objectAtIndex:1] intValue];
|
|
//NSLog(@"buy/sell all of item %d (you have %d)",item,yours);
|
|
if ((yours > 0)&&(![self marketFlooded:item])) // sell all you can
|
|
{
|
|
int i;
|
|
for (i = 0; i < yours; i++)
|
|
[self trySellingCommodity:item];
|
|
//NSLog(@"... you sold %d.", yours);
|
|
#ifdef HAVE_SOUND
|
|
if ([sellSound isPlaying])
|
|
[sellSound stop];
|
|
[sellSound play];
|
|
#endif
|
|
[self setGuiToMarketScreen];
|
|
}
|
|
else // buy as much as possible
|
|
{
|
|
int amount_bought = 0;
|
|
while ([self tryBuyingCommodity:item])
|
|
amount_bought++;
|
|
//NSLog(@"... you bought %d.", amount_bought);
|
|
[self setGuiToMarketScreen];
|
|
if (amount_bought == 0)
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if ([boopSound isPlaying])
|
|
[boopSound stop];
|
|
[boopSound play];
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if ([buySound isPlaying])
|
|
[buySound stop];
|
|
[buySound play];
|
|
#endif
|
|
}
|
|
}
|
|
wait_for_key_up = YES;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wait_for_key_up = NO;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case GUI_SCREEN_CONTRACTS :
|
|
if (status == STATUS_DOCKED)
|
|
{
|
|
if ([gameView isDown:gvArrowKeyDown])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
int next_row = [gui selectedRow] + 1;
|
|
if (![[gui keyForRow:next_row] isEqual:GUI_KEY_OK])
|
|
{
|
|
while ((![[gui keyForRow:next_row] isEqual:GUI_KEY_OK])&&(next_row < GUI_ROW_MARKET_CASH))
|
|
next_row++;
|
|
}
|
|
if ([gui setSelectedRow:next_row])
|
|
{
|
|
[gui click];
|
|
[self setGuiToContractsScreen];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
if ([gameView isDown:gvArrowKeyUp])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
int next_row = [gui selectedRow] - 1;
|
|
if (![[gui keyForRow:next_row] isEqual:GUI_KEY_OK])
|
|
{
|
|
while ((![[gui keyForRow:next_row] isEqual:GUI_KEY_OK])&&(next_row > GUI_ROW_PASSENGERS_START))
|
|
next_row--;
|
|
}
|
|
if ([gui setSelectedRow:next_row])
|
|
{
|
|
[gui click];
|
|
[self setGuiToContractsScreen];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
upDownKeyPressed = (([gameView isDown:gvArrowKeyUp])||([gameView isDown:gvArrowKeyDown]));
|
|
//
|
|
if ((status == STATUS_DOCKED)&&([gameView isDown:13])) // 'enter'
|
|
{
|
|
if (!selectPressed)
|
|
{
|
|
if ([self pickFromGuiContractsScreen])
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if ([buySound isPlaying])
|
|
[buySound stop];
|
|
[buySound play];
|
|
#endif
|
|
[self setGuiToContractsScreen];
|
|
}
|
|
else
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if ([boopSound isPlaying])
|
|
[boopSound stop];
|
|
[boopSound play];
|
|
#endif
|
|
}
|
|
}
|
|
selectPressed = YES;
|
|
}
|
|
else
|
|
{
|
|
selectPressed = NO;
|
|
}
|
|
//
|
|
if ([gameView isDown:63]) // '?' toggle between contracts screen and map
|
|
{
|
|
if (!queryPressed)
|
|
{
|
|
oldSelection = [gui selectedRow];
|
|
[self highlightSystemFromGuiContractsScreen];
|
|
}
|
|
queryPressed = YES;
|
|
}
|
|
else
|
|
queryPressed = NO;
|
|
}
|
|
break;
|
|
|
|
case GUI_SCREEN_REPORT :
|
|
if ([gameView isDown:32]) // spacebar
|
|
{
|
|
[gui click];
|
|
[self setGuiToStatusScreen];
|
|
}
|
|
break;
|
|
|
|
case GUI_SCREEN_SHIPYARD :
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
if ([gameView isDown:gvArrowKeyDown])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([gui setSelectedRow:[gui selectedRow] + 1])
|
|
{
|
|
[gui click];
|
|
[self showShipyardInfoForSelection];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
if ([gameView isDown:gvArrowKeyUp])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([gui setSelectedRow:[gui selectedRow] - 1])
|
|
{
|
|
[gui click];
|
|
[self showShipyardInfoForSelection];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
if ([gameView isDown:gvArrowKeyLeft])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([[gui keyForRow:GUI_ROW_SHIPYARD_START] hasPrefix:@"More:"])
|
|
{
|
|
[gui click];
|
|
[gui setSelectedRow:GUI_ROW_SHIPYARD_START];
|
|
[self buySelectedShip];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
if ([gameView isDown:gvArrowKeyRight])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([[gui keyForRow:GUI_ROW_SHIPYARD_START + MAX_ROWS_SHIPS_FOR_SALE - 1] hasPrefix:@"More:"])
|
|
{
|
|
[gui click];
|
|
[gui setSelectedRow:GUI_ROW_SHIPYARD_START + MAX_ROWS_SHIPS_FOR_SALE - 1];
|
|
[self buySelectedShip];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
upDownKeyPressed = (([gameView isDown:gvArrowKeyUp])||([gameView isDown:gvArrowKeyDown])||([gameView isDown:gvArrowKeyLeft])||([gameView isDown:gvArrowKeyRight]));
|
|
|
|
if ([gameView isDown:13]) // 'enter'
|
|
{
|
|
if (!selectPressed)
|
|
{
|
|
// try to buy the ship!
|
|
int money = credits;
|
|
if ([self buySelectedShip])
|
|
{
|
|
if (money == credits) // we just skipped to another page
|
|
{
|
|
[[universe gui] click];
|
|
}
|
|
else
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if ([buySound isPlaying])
|
|
[buySound stop];
|
|
[buySound play];
|
|
#endif
|
|
[universe removeDemoShips];
|
|
[self setGuiToStatusScreen];
|
|
[self setShowDemoShips:NO];
|
|
[universe setDisplayText:YES];
|
|
[universe setDisplayCursor:NO];
|
|
}
|
|
}
|
|
#ifdef HAVE_SOUND
|
|
else
|
|
{
|
|
if ([boopSound isPlaying])
|
|
[boopSound stop];
|
|
[boopSound play];
|
|
}
|
|
#endif
|
|
}
|
|
selectPressed = YES;
|
|
}
|
|
else
|
|
{
|
|
selectPressed = NO;
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// damp any rotations we entered with
|
|
//
|
|
if (flight_roll > 0.0)
|
|
{
|
|
if (flight_roll > delta_t) [self decrease_flight_roll:delta_t];
|
|
else flight_roll = 0.0;
|
|
}
|
|
if (flight_roll < 0.0)
|
|
{
|
|
if (flight_roll < -delta_t) [self increase_flight_roll:delta_t];
|
|
else flight_roll = 0.0;
|
|
}
|
|
if (flight_pitch > 0.0)
|
|
{
|
|
if (flight_pitch > delta_t) [self decrease_flight_pitch:delta_t];
|
|
else flight_pitch = 0.0;
|
|
}
|
|
if (flight_pitch < 0.0)
|
|
{
|
|
if (flight_pitch < -delta_t) [self increase_flight_pitch:delta_t];
|
|
else flight_pitch = 0.0;
|
|
}
|
|
}
|
|
|
|
- (void) pollViewControls
|
|
{
|
|
MyOpenGLView *gameView = (MyOpenGLView *)[universe gameView];
|
|
//
|
|
// view keys
|
|
//
|
|
if (([gameView isDown:gvFunctionKey1])||([gameView isDown:gvNumberKey1]))
|
|
{
|
|
if ([universe displayGUI])
|
|
{
|
|
gui_screen = GUI_SCREEN_MAIN;
|
|
[gameView allowStringInput:NO];
|
|
[universe setDisplayCursor:NO];
|
|
}
|
|
[universe setViewDirection:VIEW_FORWARD];
|
|
}
|
|
if (([gameView isDown:gvFunctionKey2])||([gameView isDown:gvNumberKey2]))
|
|
{
|
|
if ([universe displayGUI])
|
|
{
|
|
gui_screen = GUI_SCREEN_MAIN;
|
|
[gameView allowStringInput:NO];
|
|
[universe setDisplayCursor:NO];
|
|
}
|
|
[universe setViewDirection:VIEW_AFT];
|
|
}
|
|
if (([gameView isDown:gvFunctionKey3])||([gameView isDown:gvNumberKey3]))
|
|
{
|
|
if ([universe displayGUI])
|
|
{
|
|
gui_screen = GUI_SCREEN_MAIN;
|
|
[gameView allowStringInput:NO];
|
|
[universe setDisplayCursor:NO];
|
|
}
|
|
[universe setViewDirection:VIEW_PORT];
|
|
}
|
|
if (([gameView isDown:gvFunctionKey4])||([gameView isDown:gvNumberKey4]))
|
|
{
|
|
if ([universe displayGUI])
|
|
{
|
|
gui_screen = GUI_SCREEN_MAIN;
|
|
[gameView allowStringInput:NO];
|
|
[universe setDisplayCursor:NO];
|
|
}
|
|
[universe setViewDirection:VIEW_STARBOARD];
|
|
}
|
|
//
|
|
// Zoom scanner 'z'
|
|
//
|
|
if ([gameView isDown:key_scanner_zoom]) // look for the 'z' key
|
|
{
|
|
if (!zoom_pressed)
|
|
{
|
|
double zoom = [hud scanner_zoom];
|
|
if (zoom < SCANNER_MAX_ZOOM)
|
|
zoom += 1.0;
|
|
else
|
|
zoom = 1.0;
|
|
[hud setScannerZoom:zoom];
|
|
}
|
|
zoom_pressed = YES;
|
|
}
|
|
else
|
|
{
|
|
zoom_pressed = NO;
|
|
}
|
|
//
|
|
// Compass mode '/'
|
|
//
|
|
if ([gameView isDown:key_next_compass_mode]) // look for the '/' key
|
|
{
|
|
if ((!compass_mode_pressed)&&(compass_mode != COMPASS_MODE_BASIC))
|
|
[self setNextCompassMode];
|
|
compass_mode_pressed = YES;
|
|
}
|
|
else
|
|
{
|
|
compass_mode_pressed = NO;
|
|
}
|
|
//
|
|
// show comms log '`'
|
|
//
|
|
if ([gameView isDown:key_comms_log])
|
|
{
|
|
[universe showCommsLog: 1.5];
|
|
[hud refreshLastTransmitter];
|
|
}
|
|
}
|
|
|
|
static BOOL switching_chart_screens;
|
|
static BOOL switching_status_screens;
|
|
static BOOL switching_market_screens;
|
|
static BOOL switching_equipship_screens;
|
|
- (void) pollGuiScreenControls
|
|
{
|
|
MyOpenGLView *gameView = (MyOpenGLView *)[universe gameView];
|
|
BOOL docked_okay = (status == STATUS_DOCKED) || ((status == STATUS_DEMO) && (gui_screen == GUI_SCREEN_SHIPYARD));
|
|
//
|
|
// text displays
|
|
//
|
|
if (([gameView isDown:gvFunctionKey5])||([gameView isDown:gvNumberKey5]))
|
|
{
|
|
if (!switching_status_screens)
|
|
{
|
|
switching_status_screens = YES;
|
|
if ((gui_screen == GUI_SCREEN_STATUS)&&(![universe strict]))
|
|
[self setGuiToManifestScreen];
|
|
else
|
|
[self setGuiToStatusScreen];
|
|
[self checkScript];
|
|
[universe setDisplayText:YES];
|
|
[universe setDisplayCursor:NO];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switching_status_screens = NO;
|
|
}
|
|
|
|
if (([gameView isDown:gvFunctionKey6])||([gameView isDown:gvNumberKey6]))
|
|
{
|
|
if (!switching_chart_screens)
|
|
{
|
|
switching_chart_screens = YES;
|
|
if (gui_screen == GUI_SCREEN_SHORT_RANGE_CHART)
|
|
[self setGuiToLongRangeChartScreen];
|
|
else
|
|
[self setGuiToShortRangeChartScreen];
|
|
[universe setDisplayText:YES];
|
|
[universe setDisplayCursor:YES];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switching_chart_screens = NO;
|
|
}
|
|
|
|
if (([gameView isDown:gvFunctionKey7])||([gameView isDown:gvNumberKey7]))
|
|
{
|
|
if (gui_screen != GUI_SCREEN_SYSTEM_DATA)
|
|
{
|
|
[self setGuiToSystemDataScreen];
|
|
[self checkScript];
|
|
}
|
|
[universe setDisplayText:YES];
|
|
[universe setDisplayCursor:NO];
|
|
}
|
|
|
|
|
|
if (docked_okay)
|
|
{
|
|
if ((([gameView isDown:gvFunctionKey2])||([gameView isDown:gvNumberKey2]))&&(gui_screen != GUI_SCREEN_OPTIONS))
|
|
{
|
|
[gameView clearKeys];
|
|
[self setGuiToLoadSaveScreen];
|
|
[universe setDisplayCursor:NO];
|
|
}
|
|
//
|
|
if (([gameView isDown:gvFunctionKey3])||([gameView isDown:gvNumberKey3]))
|
|
{
|
|
if (!switching_equipship_screens)
|
|
{
|
|
if (!docked_station)
|
|
docked_station = [universe station];
|
|
if ((gui_screen == GUI_SCREEN_EQUIP_SHIP)&&(docked_station == [universe station])&&(![universe strict]))
|
|
{
|
|
[gameView clearKeys];
|
|
[self setGuiToShipyardScreen:0];
|
|
[[universe gui] setSelectedRow:GUI_ROW_SHIPYARD_START];
|
|
[self showShipyardInfoForSelection];
|
|
}
|
|
else
|
|
{
|
|
[gameView clearKeys];
|
|
[self setGuiToEquipShipScreen:0:-1];
|
|
[[universe gui] setSelectedRow:GUI_ROW_EQUIPMENT_START];
|
|
[universe guiUpdated];
|
|
}
|
|
[universe setDisplayCursor:NO];
|
|
}
|
|
switching_equipship_screens = YES;
|
|
}
|
|
else
|
|
{
|
|
switching_equipship_screens = NO;
|
|
}
|
|
//
|
|
if (([gameView isDown:gvFunctionKey8])||([gameView isDown:gvNumberKey8]))
|
|
{
|
|
if (!switching_market_screens)
|
|
{
|
|
if ((gui_screen == GUI_SCREEN_MARKET)&&(docked_station == [universe station])&&(![universe strict]))
|
|
{
|
|
[gameView clearKeys];
|
|
[self setGuiToContractsScreen];
|
|
[[universe gui] setSelectedRow:GUI_ROW_PASSENGERS_START];
|
|
[universe guiUpdated];
|
|
}
|
|
else
|
|
{
|
|
[gameView clearKeys];
|
|
[self setGuiToMarketScreen];
|
|
[[universe gui] setSelectedRow:GUI_ROW_MARKET_START];
|
|
[universe guiUpdated];
|
|
}
|
|
[universe setDisplayText:YES];
|
|
[universe setDisplayCursor:NO];
|
|
}
|
|
switching_market_screens = YES;
|
|
}
|
|
else
|
|
{
|
|
switching_market_screens = NO;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (([gameView isDown:gvFunctionKey8])||([gameView isDown:gvNumberKey8]))
|
|
{
|
|
if (!switching_market_screens)
|
|
{
|
|
[self setGuiToMarketScreen];
|
|
[[universe gui] setSelectedRow:GUI_ROW_MARKET_START];
|
|
[universe guiUpdated];
|
|
[universe setDisplayText:YES];
|
|
[universe setDisplayCursor:NO];
|
|
}
|
|
switching_market_screens = YES;
|
|
}
|
|
else
|
|
{
|
|
switching_market_screens = NO;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) pollGameOverControls:(double) delta_t
|
|
{
|
|
MyOpenGLView *gameView = (MyOpenGLView *)[universe gameView];
|
|
if ([gameView isDown:32]) // look for the spacebar
|
|
{
|
|
[universe displayMessage:@"" forCount:1.0];
|
|
[self set_up];
|
|
[universe game_over]; // restart
|
|
//[breakPatternSound play];
|
|
}
|
|
}
|
|
|
|
static BOOL toggling_music;
|
|
- (void) pollAutopilotControls:(double) delta_t
|
|
{
|
|
//
|
|
// controls polled while the autopilot is active
|
|
//
|
|
|
|
MyOpenGLView *gameView = (MyOpenGLView *)[universe gameView];
|
|
//
|
|
// view keys
|
|
//
|
|
[self pollViewControls];
|
|
//
|
|
// text displays
|
|
//
|
|
[self pollGuiScreenControls];
|
|
//
|
|
if ([universe displayGUI])
|
|
[self pollGuiArrowKeyControls:delta_t];
|
|
//
|
|
//
|
|
if (([gameView isDown:key_autopilot])&&(has_docking_computer)&&(![beepSound isPlaying])) // look for the 'c' key
|
|
{
|
|
[self abortDocking]; // let the station know that you are no longer on approach
|
|
condition = CONDITION_IDLE;
|
|
frustration = 0.0;
|
|
autopilot_engaged = NO;
|
|
primaryTarget = NO_TARGET;
|
|
status = STATUS_IN_FLIGHT;
|
|
#ifdef HAVE_SOUND
|
|
[beepSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[autopilot-off]" forSystem:system_seed] forCount:4.5];
|
|
//
|
|
if (ootunes_on)
|
|
{
|
|
// ootunes - play inflight music
|
|
[[universe gameController] playiTunesPlaylist:@"Oolite-Inflight"];
|
|
}
|
|
else
|
|
{
|
|
if (docking_music_on)
|
|
{
|
|
#ifndef GNUSTEP
|
|
StopMovie ([dockingMusic QTMovie]);
|
|
#else
|
|
[dockingMusic stop];
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
//
|
|
if (([gameView isDown:key_docking_music])&&(!ootunes_on)) // look for the 's' key
|
|
{
|
|
if (!toggling_music)
|
|
{
|
|
docking_music_on = !docking_music_on;
|
|
if (docking_music_on)
|
|
{
|
|
#ifndef GNUSTEP
|
|
if (IsMovieDone ([dockingMusic QTMovie]))
|
|
GoToBeginningOfMovie ([dockingMusic QTMovie]);
|
|
StartMovie ([dockingMusic QTMovie]);
|
|
#else
|
|
[dockingMusic stop];
|
|
[dockingMusic goToBeginning];
|
|
[dockingMusic play];
|
|
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifndef GNUSTEP
|
|
StopMovie ([dockingMusic QTMovie]);
|
|
#else
|
|
[dockingMusic stop];
|
|
#endif
|
|
}
|
|
}
|
|
toggling_music = YES;
|
|
}
|
|
else
|
|
{
|
|
toggling_music = NO;
|
|
}
|
|
//
|
|
// keep music playing
|
|
if ((docking_music_on)&&(!ootunes_on))
|
|
{
|
|
#ifndef GNUSTEP
|
|
if (IsMovieDone ([dockingMusic QTMovie]))
|
|
{
|
|
GoToBeginningOfMovie ([dockingMusic QTMovie]);
|
|
StartMovie ([dockingMusic QTMovie]);
|
|
}
|
|
#else
|
|
if ([dockingMusic isPlaying] == NO)
|
|
{
|
|
[dockingMusic goToBeginning];
|
|
[dockingMusic play];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
- (void) pollDockedControls:(double) delta_t
|
|
{
|
|
MyOpenGLView *gameView = (MyOpenGLView *)[universe gameView];
|
|
if (([gameView isDown:gvFunctionKey1])||([gameView isDown:gvNumberKey1])) // look for the f1 key
|
|
{
|
|
[universe set_up_universe_from_station]; // launch!
|
|
if (!docked_station)
|
|
docked_station = [universe station];
|
|
//NSLog(@"Leaving dock (%@)...%@",docked_station,[docked_station name]);
|
|
[self leaveDock:docked_station];
|
|
[universe setDisplayCursor:NO];
|
|
#ifdef HAVE_SOUND
|
|
[breakPatternSound play];
|
|
#endif
|
|
}
|
|
//
|
|
// text displays
|
|
//
|
|
[self pollGuiScreenControls];
|
|
//
|
|
[self pollGuiArrowKeyControls:delta_t];
|
|
//
|
|
//
|
|
}
|
|
|
|
- (void) pollDemoControls:(double) delta_t
|
|
{
|
|
MyOpenGLView* gameView = (MyOpenGLView *)[universe gameView];
|
|
GuiDisplayGen* gui = [universe gui];
|
|
|
|
switch (gui_screen)
|
|
{
|
|
case GUI_SCREEN_INTRO1 :
|
|
if (!disc_operation_in_progress)
|
|
{
|
|
if (([gameView isDown:121])||([gameView isDown:89])) // 'yY'
|
|
{
|
|
if (themeMusic)
|
|
{
|
|
#ifndef GNUSTEP
|
|
StopMovie ([themeMusic QTMovie]);
|
|
GoToBeginningOfMovie ([themeMusic QTMovie]);
|
|
#else
|
|
[themeMusic stop];
|
|
[themeMusic goToBeginning];
|
|
#endif
|
|
}
|
|
|
|
disc_operation_in_progress = YES;
|
|
if ([[universe gameController] inFullScreenMode])
|
|
[[universe gameController] pauseFullScreenModeToPerform:@selector(loadPlayer) onTarget:self];
|
|
else
|
|
[self loadPlayer];
|
|
[self setStatus:STATUS_DOCKED];
|
|
[self setGuiToStatusScreen];
|
|
[universe setDisplayText:YES];
|
|
}
|
|
}
|
|
if (([gameView isDown:110])||([gameView isDown:78])) // 'nN'
|
|
{
|
|
[self setGuiToIntro2Screen];
|
|
}
|
|
|
|
// // test exception handling
|
|
// if ([gameView isDown:48]) // '0'
|
|
// {
|
|
// NSException* myException = [NSException
|
|
// exceptionWithName: @"TestException"
|
|
// reason: @"The Foo throggled the Bar!"
|
|
// userInfo: nil];
|
|
// [myException raise];
|
|
// }
|
|
|
|
break;
|
|
|
|
case GUI_SCREEN_INTRO2 :
|
|
if ([gameView isDown:32]) // '<space>'
|
|
{
|
|
//docked_station = [universe station];
|
|
[self setStatus:STATUS_DOCKED];
|
|
[universe removeDemoShips];
|
|
[gui setBackgroundImage:nil];
|
|
[self setGuiToStatusScreen];
|
|
[universe setDisplayText:YES];
|
|
if (themeMusic)
|
|
{
|
|
#ifndef GNUSTEP
|
|
StopMovie ([themeMusic QTMovie]);
|
|
GoToBeginningOfMovie ([themeMusic QTMovie]);
|
|
#else
|
|
[themeMusic stop];
|
|
[themeMusic goToBeginning];
|
|
#endif
|
|
}
|
|
}
|
|
if ([gameView isDown:gvArrowKeyLeft]) // '<--'
|
|
{
|
|
if (!upDownKeyPressed)
|
|
[universe selectIntro2Previous];
|
|
}
|
|
if ([gameView isDown:gvArrowKeyRight]) // '-->'
|
|
{
|
|
if (!upDownKeyPressed)
|
|
[universe selectIntro2Next];
|
|
}
|
|
upDownKeyPressed = (([gameView isDown:gvArrowKeyLeft])||([gameView isDown:gvArrowKeyRight]));
|
|
break;
|
|
|
|
case GUI_SCREEN_MISSION :
|
|
if ([[gui keyForRow:21] isEqual:@"spacebar"])
|
|
{
|
|
if ([gameView isDown:32]) // '<space>'
|
|
{
|
|
[self setStatus:STATUS_DOCKED];
|
|
[universe removeDemoShips];
|
|
[gui setBackgroundImage:nil];
|
|
[self setGuiToStatusScreen];
|
|
[universe setDisplayText:YES];
|
|
#ifndef GNUSTEP
|
|
if (missionMusic)
|
|
{
|
|
StopMovie ([missionMusic QTMovie]);
|
|
GoToBeginningOfMovie ([missionMusic QTMovie]);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ([gameView isDown:gvArrowKeyDown])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([gui setSelectedRow:[gui selectedRow] + 1])
|
|
{
|
|
[gui click];
|
|
[universe guiUpdated];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
if ([gameView isDown:gvArrowKeyUp])
|
|
{
|
|
if ((!upDownKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
|
|
{
|
|
if ([gui setSelectedRow:[gui selectedRow] - 1])
|
|
{
|
|
[gui click];
|
|
[universe guiUpdated];
|
|
}
|
|
timeLastKeyPress = script_time;
|
|
}
|
|
}
|
|
upDownKeyPressed = (([gameView isDown:gvArrowKeyUp])||([gameView isDown:gvArrowKeyDown]));
|
|
//
|
|
if ([gameView isDown:13]) // '<enter/return>'
|
|
{
|
|
if (missionChoice)
|
|
[missionChoice release];
|
|
missionChoice = [[NSString stringWithString:[gui selectedRowKey]] retain];
|
|
//
|
|
[self setStatus:STATUS_DOCKED];
|
|
[universe removeDemoShips];
|
|
[gui setBackgroundImage:nil];
|
|
[self setGuiToStatusScreen];
|
|
[universe setDisplayText:YES];
|
|
#ifndef GNUSTEP
|
|
if (missionMusic)
|
|
{
|
|
StopMovie ([missionMusic QTMovie]);
|
|
GoToBeginningOfMovie ([missionMusic QTMovie]);
|
|
}
|
|
#endif
|
|
//
|
|
[self checkScript];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
- (void) interpretAIMessage:(NSString *)ms
|
|
{
|
|
if ([ms isEqual:@"HOLD_FULL"])
|
|
{
|
|
[boopSound play]; [beepSound play];
|
|
[universe addMessage:[universe expandDescription:@"[hold-full]" forSystem:system_seed] forCount:4.5];
|
|
}
|
|
|
|
if ([ms isEqual:@"INCOMING_MISSILE"])
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
[warningSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[incoming-missile]" forSystem:system_seed] forCount:4.5];
|
|
}
|
|
|
|
if ([ms isEqual:@"ENERGY_LOW"])
|
|
[universe addMessage:[universe expandDescription:@"[energy-low]" forSystem:system_seed] forCount:6.0];
|
|
|
|
if (([ms isEqual:@"ECM"])&&(![ecmSound isPlaying]))
|
|
#ifdef HAVE_SOUND
|
|
[ecmSound play];
|
|
#endif
|
|
|
|
if ([ms isEqual:@"DOCKING_REFUSED"]&&(status == STATUS_AUTOPILOT_ENGAGED))
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
[warningSound play];
|
|
#endif
|
|
[universe addMessage:[universe expandDescription:@"[autopilot-denied]" forSystem:system_seed] forCount:4.5];
|
|
autopilot_engaged = NO;
|
|
primaryTarget = NO_TARGET;
|
|
status = STATUS_IN_FLIGHT;
|
|
if (ootunes_on)
|
|
{
|
|
// ootunes - play inflight music
|
|
[[universe gameController] playiTunesPlaylist:@"Oolite-Inflight"];
|
|
}
|
|
else
|
|
{
|
|
if (docking_music_on)
|
|
{
|
|
#ifndef GNUSTEP
|
|
StopMovie ([dockingMusic QTMovie]);
|
|
#else
|
|
[dockingMusic stop];
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
// aegis messages to advanced compass so in planet mode it behaves like the old compass
|
|
if (compass_mode != COMPASS_MODE_BASIC)
|
|
{
|
|
if ([ms isEqual:@"AEGIS_CLOSE_TO_PLANET"]&&(compass_mode == COMPASS_MODE_PLANET))
|
|
[self setCompass_mode:COMPASS_MODE_STATION];
|
|
if ([ms isEqual:@"AEGIS_IN_DOCKING_RANGE"]&&(compass_mode == COMPASS_MODE_PLANET))
|
|
[self setCompass_mode:COMPASS_MODE_STATION];
|
|
if ([ms isEqual:@"AEGIS_NONE"]&&(compass_mode == COMPASS_MODE_STATION))
|
|
[self setCompass_mode:COMPASS_MODE_PLANET];
|
|
}
|
|
}
|
|
|
|
- (BOOL) mountMissile: (ShipEntity *)missile
|
|
{
|
|
int i;
|
|
for (i = 0; i < max_missiles; i++)
|
|
{
|
|
if (missile_entity[i] == nil)
|
|
{
|
|
missile_entity[i] = [missile retain];
|
|
return YES;
|
|
}
|
|
}
|
|
missiles = [self calc_missiles];
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL) fireMissile
|
|
{
|
|
ShipEntity *missile = missile_entity[active_missile]; // retain count is 1
|
|
|
|
if (missile == nil)
|
|
return NO;
|
|
|
|
if ([[missile roles] hasSuffix:@"MINE"]&&((missile_status == MISSILE_STATUS_ARMED)||(missile_status == MISSILE_STATUS_TARGET_LOCKED)))
|
|
{
|
|
BOOL launchedOK = [self launchMine:missile];
|
|
missile_entity[active_missile] = nil;
|
|
[self select_next_missile];
|
|
missiles = [self calc_missiles];
|
|
return launchedOK;
|
|
}
|
|
|
|
if ((missile_status != MISSILE_STATUS_TARGET_LOCKED)||(ident_engaged))
|
|
return NO;
|
|
|
|
Vector vel;
|
|
Vector origin = position;
|
|
Vector start;
|
|
start.x = 0.0; // in the middle
|
|
start.y = boundingBox.min_y - 4.0; // 4m below bounding box
|
|
start.z = boundingBox.max_z + 1.0; // 1m ahead of bounding box
|
|
double throw_speed = 250.0;
|
|
Quaternion q1 = q_rotation;
|
|
q1.w = -q1.w; // player view is reversed remember!
|
|
Entity *target = [self getPrimaryTarget];
|
|
|
|
// select a new active missile and decrease the missiles count
|
|
missile_entity[active_missile] = nil;
|
|
[self select_next_missile];
|
|
missiles = [self calc_missiles];
|
|
|
|
vel.x = (flight_speed + throw_speed) * v_forward.x;
|
|
vel.y = (flight_speed + throw_speed) * v_forward.y;
|
|
vel.z = (flight_speed + throw_speed) * v_forward.z;
|
|
|
|
origin.x = position.x + v_right.x * start.x + v_up.x * start.y + v_forward.x * start.z;
|
|
origin.y = position.y + v_right.y * start.x + v_up.y * start.y + v_forward.y * start.z;
|
|
origin.z = position.z + v_right.z * start.x + v_up.z * start.y + v_forward.z * start.z;
|
|
|
|
[missile setPosition:origin]; // directly below
|
|
[missile setScanClass: CLASS_MISSILE];
|
|
[missile addTarget:target];
|
|
[missile setQRotation:q1];
|
|
[missile setStatus: STATUS_IN_FLIGHT]; // necessary to get it going!
|
|
[missile setVelocity: vel];
|
|
[missile setSpeed:150.0];
|
|
[missile setOwner:self];
|
|
[missile setDistanceTravelled:0.0];
|
|
//
|
|
[universe addEntity:missile];
|
|
[missile release]; // released
|
|
|
|
[(ShipEntity *)target setPrimaryAggressor:self];
|
|
[[(ShipEntity *)target getAI] reactToMessage:@"INCOMING_MISSILE"];
|
|
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL) launchMine:(ShipEntity*) mine
|
|
{
|
|
if (!mine)
|
|
return NO;
|
|
// [self setSpeed: max_flight_speed];
|
|
double start = collision_radius + mine->collision_radius;
|
|
double eject_speed = -500.0;
|
|
Quaternion random_direction;
|
|
Vector vel;
|
|
Vector rpos = position;
|
|
double random_roll = randf() - 0.5; // -0.5 to +0.5
|
|
double random_pitch = randf() - 0.5; // -0.5 to +0.5
|
|
quaternion_set_random(&random_direction);
|
|
rpos.x -= v_forward.x * start;
|
|
rpos.y -= v_forward.y * start;
|
|
rpos.z -= v_forward.z * start;
|
|
vel.x = v_forward.x * (flight_speed + eject_speed);
|
|
vel.y = v_forward.y * (flight_speed + eject_speed);
|
|
vel.z = v_forward.z * (flight_speed + eject_speed);
|
|
eject_speed *= 0.5 * (randf() - 0.5); // -0.25x .. +0.25x
|
|
vel.x += v_up.x * eject_speed;
|
|
vel.y += v_up.y * eject_speed;
|
|
vel.z += v_up.z * eject_speed;
|
|
eject_speed *= 0.5 * (randf() - 0.5); // -0.0625x .. +0.0625x
|
|
vel.x += v_right.x * eject_speed;
|
|
vel.y += v_right.y * eject_speed;
|
|
vel.z += v_right.z * eject_speed;
|
|
[mine setPosition:rpos];
|
|
[mine setQRotation:random_direction];
|
|
[mine setRoll:random_roll];
|
|
[mine setPitch:random_pitch];
|
|
[mine setVelocity:vel];
|
|
[mine setScanClass: CLASS_MINE];
|
|
[mine setStatus: STATUS_IN_FLIGHT];
|
|
[mine setCondition: CONDITION_IDLE];
|
|
[mine setOwner: self];
|
|
[universe addEntity:mine];
|
|
// [mine setReportAImessages:YES];
|
|
[[mine getAI] setState:@"GLOBAL"]; // start the timer !!!!
|
|
[mine release];
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL) fireECM
|
|
{
|
|
if ([super fireECM])
|
|
{
|
|
ecm_in_operation = YES;
|
|
ecm_start_time = [universe getTime];
|
|
return YES;
|
|
}
|
|
else
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL) fireEnergyBomb
|
|
{
|
|
NSArray* targets = [universe getEntitiesWithinRange:SCANNER_MAX_RANGE ofEntity:self];
|
|
if ([targets count] > 0)
|
|
{
|
|
int i;
|
|
for (i = 0; i < [targets count]; i++)
|
|
{
|
|
Entity *e2 = [targets objectAtIndex:i];
|
|
if (e2->isShip)
|
|
[(ShipEntity *)e2 takeEnergyDamage:1000 from:self becauseOf:self];
|
|
}
|
|
}
|
|
[universe addMessage:[universe expandDescription:@"[energy-bomb-activated]" forSystem:system_seed] forCount:4.5];
|
|
#ifdef HAVE_SOUND
|
|
[destructionSound play];
|
|
#endif
|
|
return YES;
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) fireMainWeapon
|
|
{
|
|
int weapon_to_be_fired = [self weaponForView:[universe viewDir]];
|
|
|
|
if (weapon_temp / PLAYER_MAX_WEAPON_TEMP >= 0.85)
|
|
{
|
|
[universe addMessage:[universe expandDescription:@"[weapon-overheat]" forSystem:system_seed] forCount:3.0];
|
|
return NO;
|
|
}
|
|
|
|
if (weapon_to_be_fired == WEAPON_NONE)
|
|
return NO;
|
|
|
|
switch (weapon_to_be_fired)
|
|
{
|
|
case WEAPON_PLASMA_CANNON :
|
|
weapon_energy = 6.0;
|
|
weapon_energy_per_shot = 6.0;
|
|
weapon_heat_increment_per_shot = 8.0;
|
|
weapon_reload_time = 0.25;
|
|
weapon_range = 5000;
|
|
break;
|
|
case WEAPON_PULSE_LASER :
|
|
weapon_energy = 15.0;
|
|
weapon_energy_per_shot = 1.0;
|
|
weapon_heat_increment_per_shot = 8.0;
|
|
weapon_reload_time = 0.5;
|
|
weapon_range = 12500;
|
|
break;
|
|
case WEAPON_BEAM_LASER :
|
|
weapon_energy = 15.0;
|
|
weapon_energy_per_shot = 1.0;
|
|
weapon_heat_increment_per_shot = 8.0;
|
|
weapon_reload_time = 0.1;
|
|
weapon_range = 15000;
|
|
break;
|
|
case WEAPON_MINING_LASER :
|
|
weapon_energy = 50.0;
|
|
weapon_energy_per_shot = 1.0;
|
|
weapon_heat_increment_per_shot = 8.0;
|
|
weapon_reload_time = 2.5;
|
|
weapon_range = 12500;
|
|
break;
|
|
case WEAPON_THARGOID_LASER :
|
|
case WEAPON_MILITARY_LASER :
|
|
weapon_energy = 23.0;
|
|
weapon_energy_per_shot = 1.0;
|
|
weapon_heat_increment_per_shot = 8.0;
|
|
weapon_reload_time = 0.1;
|
|
weapon_range = 30000;
|
|
break;
|
|
}
|
|
|
|
if (energy <= weapon_energy_per_shot)
|
|
{
|
|
[universe addMessage:[universe expandDescription:@"[weapon-out-of-juice]" forSystem:system_seed] forCount:3.0];
|
|
return NO;
|
|
}
|
|
|
|
using_mining_laser = (weapon_to_be_fired == WEAPON_MINING_LASER);
|
|
|
|
energy -= weapon_energy_per_shot;
|
|
|
|
// weapon_temp += weapon_heat_increment_per_shot;
|
|
switch ([universe viewDir])
|
|
{
|
|
case VIEW_DOCKED:
|
|
case VIEW_NONE:
|
|
case VIEW_BREAK_PATTERN:
|
|
case VIEW_FORWARD:
|
|
forward_weapon_temp += weapon_heat_increment_per_shot;
|
|
break;
|
|
case VIEW_AFT:
|
|
aft_weapon_temp += weapon_heat_increment_per_shot;
|
|
break;
|
|
case VIEW_PORT:
|
|
port_weapon_temp += weapon_heat_increment_per_shot;
|
|
break;
|
|
case VIEW_STARBOARD:
|
|
starboard_weapon_temp += weapon_heat_increment_per_shot;
|
|
break;
|
|
}
|
|
|
|
//NSLog(@"%@ firing weapon",name);
|
|
switch (weapon_to_be_fired)
|
|
{
|
|
case WEAPON_PLASMA_CANNON :
|
|
[self firePlasmaShot:10.0:1000.0:[NSColor greenColor]];
|
|
return YES;
|
|
break;
|
|
|
|
case WEAPON_PULSE_LASER :
|
|
case WEAPON_BEAM_LASER :
|
|
case WEAPON_MINING_LASER :
|
|
case WEAPON_MILITARY_LASER :
|
|
[self fireLaserShot];
|
|
return YES;
|
|
break;
|
|
case WEAPON_THARGOID_LASER :
|
|
[self fireDirectLaserShot];
|
|
return YES;
|
|
break;
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
- (int) weaponForView:(int) view
|
|
{
|
|
switch (view)
|
|
{
|
|
case VIEW_PORT :
|
|
return port_weapon;
|
|
break;
|
|
case VIEW_STARBOARD :
|
|
return starboard_weapon;
|
|
break;
|
|
case VIEW_AFT :
|
|
return aft_weapon;
|
|
break;
|
|
case VIEW_FORWARD :
|
|
default :
|
|
return forward_weapon;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
- (void) takeEnergyDamage:(double) amount from:(Entity *) ent becauseOf:(Entity *) other
|
|
{
|
|
Vector rel_pos;
|
|
double d_forward;
|
|
|
|
if (status == STATUS_DEAD)
|
|
return;
|
|
if (amount == 0.0)
|
|
return;
|
|
|
|
[ent retain];
|
|
[other retain];
|
|
rel_pos = (ent)? ent->position: make_vector(0,0,0);
|
|
|
|
rel_pos.x -= position.x;
|
|
rel_pos.y -= position.y;
|
|
rel_pos.z -= position.z;
|
|
|
|
d_forward = dot_product(rel_pos, v_forward);
|
|
|
|
if (damageSound)
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if ([damageSound isPlaying])
|
|
[damageSound stop];
|
|
[damageSound play];
|
|
#endif
|
|
}
|
|
|
|
if (d_forward >= 0)
|
|
{
|
|
//NSLog(@"hit on FORWARD shields");
|
|
forward_shield -= amount;
|
|
if (forward_shield < 0.0)
|
|
{
|
|
amount = -forward_shield;
|
|
forward_shield = 0.0;
|
|
}
|
|
else
|
|
{
|
|
amount = 0.0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//NSLog(@"hit on AFT shields");
|
|
aft_shield -= amount;
|
|
if (aft_shield < 0.0)
|
|
{
|
|
amount = -aft_shield;
|
|
aft_shield = 0.0;
|
|
}
|
|
else
|
|
{
|
|
amount = 0.0;
|
|
}
|
|
}
|
|
|
|
if (amount > 0.0)
|
|
{
|
|
energy -= amount;
|
|
if (scrapeDamageSound)
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if ([scrapeDamageSound isPlaying])
|
|
[scrapeDamageSound stop];
|
|
[scrapeDamageSound play];
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (energy <= 0.0)
|
|
{
|
|
if ((other)&&(other->isShip))
|
|
{
|
|
ShipEntity* hunter = (ShipEntity *)other;
|
|
[hunter collectBountyFor:self];
|
|
if ([hunter getPrimaryTarget] == (Entity *)self)
|
|
{
|
|
[hunter removeTarget:(Entity *)self];
|
|
[[hunter getAI] message:@"TARGET_DESTROYED"];
|
|
}
|
|
}
|
|
[self getDestroyed];
|
|
}
|
|
|
|
[ent release];
|
|
[other release];
|
|
//
|
|
}
|
|
|
|
- (void) takeScrapeDamage:(double) amount from:(Entity *) ent
|
|
{
|
|
Vector rel_pos;
|
|
double d_forward;
|
|
|
|
if (status == STATUS_DEAD)
|
|
return;
|
|
|
|
[ent retain];
|
|
rel_pos = (ent)? ent->position : make_vector(0,0,0);
|
|
|
|
rel_pos.x -= position.x;
|
|
rel_pos.y -= position.y;
|
|
rel_pos.z -= position.z;
|
|
|
|
d_forward = dot_product(rel_pos, v_forward);
|
|
|
|
if (scrapeDamageSound)
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if ([scrapeDamageSound isPlaying])
|
|
[scrapeDamageSound stop];
|
|
[scrapeDamageSound play];
|
|
#endif
|
|
}
|
|
if (d_forward >= 0)
|
|
{
|
|
forward_shield -= amount;
|
|
if (forward_shield < 0.0)
|
|
{
|
|
amount = -forward_shield;
|
|
forward_shield = 0.0;
|
|
}
|
|
else
|
|
{
|
|
amount = 0.0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aft_shield -= amount;
|
|
if (aft_shield < 0.0)
|
|
{
|
|
amount = -aft_shield;
|
|
aft_shield = 0.0;
|
|
}
|
|
else
|
|
{
|
|
amount = 0.0;
|
|
}
|
|
}
|
|
|
|
energy -= amount;
|
|
if (energy <= 0.0)
|
|
{
|
|
if ((ent)&&(ent->isShip))
|
|
{
|
|
ShipEntity* hunter = (ShipEntity *)ent;
|
|
[hunter collectBountyFor:self];
|
|
if ([hunter getPrimaryTarget] == (Entity *)self)
|
|
{
|
|
[hunter removeTarget:(Entity *)self];
|
|
[[hunter getAI] message:@"TARGET_DESTROYED"];
|
|
}
|
|
}
|
|
[self getDestroyed];
|
|
}
|
|
//
|
|
[ent release];
|
|
}
|
|
|
|
- (int) launchEscapeCapsule
|
|
{
|
|
ShipEntity *doppelganger;
|
|
Vector vel;
|
|
Vector origin = position;
|
|
int result;
|
|
//double start = 10.0;
|
|
//double throw_speed = 20.0;
|
|
Quaternion q1 = q_rotation;
|
|
|
|
status = STATUS_ESCAPE_SEQUENCE; // firstly
|
|
ship_clock_adjust += 43200 + 5400 * (ranrot_rand() & 127); // add up to 8 days until rescue!
|
|
|
|
q1.w = -q1.w; // player view is reversed remember!
|
|
|
|
if (flight_speed < 50.0)
|
|
flight_speed = 50.0;
|
|
|
|
vel.x = flight_speed * v_forward.x;
|
|
vel.y = flight_speed * v_forward.y;
|
|
vel.z = flight_speed * v_forward.z;
|
|
|
|
doppelganger = [universe getShip: ship_desc]; // retain count = 1
|
|
[doppelganger setPosition: origin]; // directly below
|
|
[doppelganger setScanClass: CLASS_NEUTRAL];
|
|
[doppelganger setQRotation: q1];
|
|
[doppelganger setVelocity: vel];
|
|
[doppelganger setSpeed: flight_speed];
|
|
[doppelganger setRoll:0.2 * (randf() - 0.5)];
|
|
[doppelganger setDesiredSpeed: flight_speed];
|
|
[doppelganger setOwner: self];
|
|
[doppelganger setStatus: STATUS_IN_FLIGHT]; // necessary to get it going!
|
|
[doppelganger setCondition: CONDITION_IDLE];
|
|
|
|
[universe addEntity:doppelganger];
|
|
|
|
[[doppelganger getAI] setStateMachine:@"nullAI.plist"]; // fly straight on
|
|
|
|
result = [doppelganger universal_id];
|
|
|
|
[doppelganger release]; //release
|
|
|
|
// set up you
|
|
[self setModel:@"capsule.dat"]; // look right to anyone else (for multiplayer later)
|
|
[universe setViewDirection:VIEW_FORWARD];
|
|
flight_speed = 1.0;
|
|
flight_pitch = 0.2 * (randf() - 0.5);
|
|
flight_roll = 0.2 * (randf() - 0.5);
|
|
|
|
double sheight = (boundingBox.max_y - boundingBox.min_y);
|
|
position.x -= sheight * v_up.x;
|
|
position.y -= sheight * v_up.y;
|
|
position.z -= sheight * v_up.z;
|
|
|
|
//remove escape pod
|
|
[self remove_extra_equipment:@"EQ_ESCAPE_POD"];
|
|
//has_escape_pod = NO;
|
|
|
|
// reset legal status
|
|
legal_status = 0;
|
|
bounty = 0;
|
|
|
|
// remove cargo
|
|
[cargo removeAllObjects];
|
|
|
|
energy = 25;
|
|
[universe addMessage:[universe expandDescription:@"[escape-sequence]" forSystem:system_seed] forCount:4.5];
|
|
shot_time = 0.0;
|
|
|
|
return result;
|
|
}
|
|
|
|
- (int) dumpCargo
|
|
{
|
|
int result = [super dumpCargo];
|
|
if (result != CARGO_NOT_CARGO)
|
|
{
|
|
[universe addMessage:[NSString stringWithFormat:[universe expandDescription:@"[@-ejected]" forSystem:system_seed],[universe nameForCommodity:result]] forCount:3.0];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
- (int) getBounty // overrides returning 'bounty'
|
|
{
|
|
return legal_status;
|
|
}
|
|
- (int) legal_status
|
|
{
|
|
return legal_status;
|
|
}
|
|
|
|
- (void) markAsOffender:(int)offence_value
|
|
{
|
|
legal_status |= offence_value;
|
|
}
|
|
|
|
- (void) collectBountyFor:(ShipEntity *)other
|
|
{
|
|
if (!other)
|
|
return;
|
|
int score = 10 * [other getBounty];
|
|
int killClass = other->scan_class; // **tgape** change (+line)
|
|
int kill_award = 1;
|
|
//
|
|
if ([[other roles] isEqual:@"police"]) // oops, we shot a copper!
|
|
legal_status |= 64;
|
|
//
|
|
if (![universe strict]) // only mess with the scores if we're not in 'strict' mode
|
|
{
|
|
// NSLog(@"DEBUG universe not strict killClass is %d", killClass);
|
|
if ((killClass == CLASS_CARGO)||(killClass == CLASS_BUOY)||(killClass == CLASS_ROCK))
|
|
{
|
|
// NSLog(@"DEBUG killClass not suitable for high reward");
|
|
if (![[other roles] isEqual:@"tharglet"]) // okay, we'll count tharglets as proper kills
|
|
{
|
|
// NSLog(@"DEBUG reducing award");
|
|
score /= 10; // reduce bounty awarded
|
|
kill_award = 0; // don't award a kill
|
|
}
|
|
}
|
|
}
|
|
//
|
|
credits += score;
|
|
//
|
|
NSString* bonusMS1 = [NSString stringWithFormat:[universe expandDescription:@"[bounty-d]" forSystem:system_seed], score / 10];
|
|
NSString* bonusMS2 = [NSString stringWithFormat:[universe expandDescription:@"[total-f-credits]" forSystem:system_seed], 0.1 * credits];
|
|
//
|
|
[universe addDelayedMessage:bonusMS1 forCount:6 afterDelay:0.15];
|
|
[universe addDelayedMessage:bonusMS2 forCount:6 afterDelay:0.15];
|
|
//
|
|
while (kill_award > 0)
|
|
{
|
|
ship_kills++;
|
|
kill_award--;
|
|
if ((ship_kills % 256) == 0)
|
|
{
|
|
// congratulations method needs to be delayed a fraction of a second
|
|
NSString* roc = [universe expandDescription:@"[right-on-commander]" forSystem:system_seed];
|
|
[universe addDelayedMessage:roc forCount:4 afterDelay:0.2];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) getDestroyed
|
|
{
|
|
NSString* scoreMS = [NSString stringWithFormat:@"Score: %.1f Credits",credits/10.0];
|
|
energy = 0.0;
|
|
afterburner_engaged = NO;
|
|
[universe setDisplayText:NO];
|
|
[universe setDisplayCursor:NO];
|
|
[universe setViewDirection:VIEW_AFT];
|
|
[self becomeLargeExplosion:4.0];
|
|
[self moveForward:100.0];
|
|
|
|
// todo some check for ootunes
|
|
if (dockingMusic)
|
|
{
|
|
if ([dockingMusic isPlaying])
|
|
[dockingMusic stop];
|
|
}
|
|
|
|
#ifdef HAVE_SOUND
|
|
[destructionSound play];
|
|
#endif
|
|
flight_speed = 160.0;
|
|
status = STATUS_DEAD;
|
|
[universe displayMessage:@"Game Over" forCount:30.0];
|
|
[universe displayMessage:@"" forCount:30.0];
|
|
[universe displayMessage:scoreMS forCount:30.0];
|
|
[universe displayMessage:@"" forCount:30.0];
|
|
[universe displayMessage:@"Press Space" forCount:30.0];
|
|
shot_time = 0.0;
|
|
|
|
[self loseTargetStatus];
|
|
}
|
|
|
|
- (void) loseTargetStatus
|
|
{
|
|
if (!universe)
|
|
return;
|
|
int ent_count = universe->n_entities;
|
|
Entity** uni_entities = universe->sortedEntities; // grab the public sorted list
|
|
Entity* my_entities[ent_count];
|
|
int i;
|
|
for (i = 0; i < ent_count; i++)
|
|
my_entities[i] = [uni_entities[i] retain]; // retained
|
|
for (i = 0; i < ent_count ; i++)
|
|
{
|
|
Entity* thing = my_entities[i];
|
|
if (thing->isShip)
|
|
{
|
|
ShipEntity* ship = (ShipEntity *)thing;
|
|
if (self == [ship getPrimaryTarget])
|
|
{
|
|
[[ship getAI] message:@"TARGET_LOST"];
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < ent_count; i++)
|
|
[my_entities[i] release]; // released
|
|
}
|
|
|
|
- (void) enterDock:(StationEntity *)station
|
|
{
|
|
status = STATUS_DOCKING;
|
|
|
|
afterburner_engaged = NO;
|
|
|
|
cloaking_device_active = NO;
|
|
hyperspeed_engaged = NO;
|
|
hyperspeed_locked = NO;
|
|
missile_status = MISSILE_STATUS_SAFE;
|
|
|
|
[hud setScannerZoom:1.0];
|
|
[universe setDisplayText:NO];
|
|
[universe setDisplayCursor:NO];
|
|
[universe set_up_break_pattern:position quaternion:q_rotation];
|
|
#ifdef HAVE_SOUND
|
|
if ([breakPatternSound isPlaying])
|
|
[breakPatternSound stop];
|
|
[breakPatternSound play];
|
|
#endif
|
|
|
|
[station noteDockedShip:self];
|
|
docked_station = station;
|
|
|
|
[(MyOpenGLView *)[universe gameView] clearKeys]; // try to stop key bounces
|
|
}
|
|
|
|
- (void) docked
|
|
{
|
|
// NSString* dockedMS = @"Docked with station.";
|
|
status = STATUS_DOCKED;
|
|
[universe setViewDirection:VIEW_DOCKED];
|
|
|
|
[self loseTargetStatus];
|
|
|
|
if (docked_station)
|
|
{
|
|
Vector launchPos = docked_station->position;
|
|
position = launchPos;
|
|
|
|
q_rotation = docked_station->q_rotation;
|
|
q_rotation.w = -q_rotation.w; // need this as a fix...
|
|
|
|
// rotate 90 degrees
|
|
quaternion_rotate_about_z(&q_rotation, PI * 0.5);
|
|
|
|
v_forward = vector_forward_from_quaternion(q_rotation);
|
|
v_right = vector_right_from_quaternion(q_rotation);
|
|
v_up = vector_up_from_quaternion(q_rotation);
|
|
|
|
q_rotation.w = -q_rotation.w; // need this as a fix...
|
|
quaternion_into_gl_matrix(q_rotation, rotMatrix);
|
|
}
|
|
|
|
flight_roll = 0.0;
|
|
flight_pitch = 0.0;
|
|
flight_speed = 0.0;
|
|
|
|
hyperspeed_engaged = NO;
|
|
hyperspeed_locked = NO;
|
|
missile_status = MISSILE_STATUS_SAFE;
|
|
|
|
primaryTarget = NO_TARGET;
|
|
|
|
forward_shield = PLAYER_MAX_FORWARD_SHIELD;
|
|
aft_shield = PLAYER_MAX_AFT_SHIELD;
|
|
energy = max_energy;
|
|
weapon_temp = 0.0;
|
|
cabin_temp = 60.0;
|
|
|
|
[self setAlert_flag:ALERT_FLAG_DOCKED :YES];
|
|
|
|
if (![docked_station localMarket])
|
|
[docked_station initialiseLocalMarketWithSeed:system_seed andRandomFactor:market_rnd];
|
|
|
|
[self unloadCargoPods];
|
|
|
|
NSString* deliveryReport = [self checkPassengerContracts];
|
|
if (deliveryReport)
|
|
[self setGuiToDeliveryReportScreenWithText:deliveryReport];
|
|
else
|
|
[self setGuiToStatusScreen];
|
|
|
|
[universe setDisplayText:YES];
|
|
// [universe displayMessage:dockedMS forCount:3.0];
|
|
|
|
if (ootunes_on)
|
|
{
|
|
// ootunes - pause current music
|
|
[[universe gameController] pauseiTunes];
|
|
// ootunes - play inflight music
|
|
[[universe gameController] playiTunesPlaylist:@"Oolite-Docked"];
|
|
}
|
|
else
|
|
{
|
|
if (docking_music_on)
|
|
{
|
|
#ifndef GNUSTEP
|
|
StopMovie ([dockingMusic QTMovie]);
|
|
#else
|
|
[dockingMusic stop];
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// time to check the script!
|
|
[self checkScript];
|
|
|
|
if (being_fined)
|
|
[self getFined];
|
|
|
|
}
|
|
|
|
- (void) leaveDock:(StationEntity *)station
|
|
{
|
|
if (station == [universe station])
|
|
legal_status |= [universe legal_status_of_manifest:shipCommodityData]; // 'leaving with those guns were you sir?'
|
|
[self loadCargoPods];
|
|
|
|
[station autoDockShipsOnApproach]; // clear the way
|
|
|
|
[station launchShip:self];
|
|
q_rotation.w = -q_rotation.w; // need this as a fix...
|
|
flight_roll = -flight_roll;
|
|
|
|
[self setAlert_flag:ALERT_FLAG_DOCKED :NO];
|
|
|
|
[hud setScannerZoom:1.0];
|
|
gui_screen = GUI_SCREEN_MAIN;
|
|
[self setShowDemoShips:NO];
|
|
[universe setDisplayText:NO];
|
|
[universe setDisplayCursor:NO];
|
|
[universe set_up_break_pattern:position quaternion:q_rotation];
|
|
#ifdef HAVE_SOUND
|
|
if ([breakPatternSound isPlaying])
|
|
[breakPatternSound stop];
|
|
[breakPatternSound play];
|
|
#endif
|
|
|
|
[(MyOpenGLView *)[universe gameView] clearKeys]; // try to stop keybounces
|
|
|
|
if (ootunes_on)
|
|
{
|
|
// ootunes - pause current music
|
|
[[universe gameController] pauseiTunes];
|
|
// ootunes - play inflight music
|
|
[[universe gameController] playiTunesPlaylist:@"Oolite-Inflight"];
|
|
}
|
|
|
|
ship_clock_adjust = 600.0; // 10 minutes to leave dock
|
|
|
|
docked_station = nil;
|
|
}
|
|
|
|
- (void) enterGalacticWitchspace
|
|
{
|
|
status = STATUS_ENTERING_WITCHSPACE;
|
|
|
|
hyperspeed_engaged = NO;
|
|
|
|
[universe setDisplayText:NO];
|
|
[universe removeAllEntitiesExceptPlayer:NO];
|
|
|
|
[self remove_extra_equipment:@"EQ_GAL_DRIVE"];
|
|
//has_galactic_hyperdrive = NO; // fuel cost to target system
|
|
|
|
galaxy_number++;
|
|
galaxy_number &= 7;
|
|
|
|
galaxy_seed.a = rotate_byte_left(galaxy_seed.a);
|
|
galaxy_seed.b = rotate_byte_left(galaxy_seed.b);
|
|
galaxy_seed.c = rotate_byte_left(galaxy_seed.c);
|
|
galaxy_seed.d = rotate_byte_left(galaxy_seed.d);
|
|
galaxy_seed.e = rotate_byte_left(galaxy_seed.e);
|
|
galaxy_seed.f = rotate_byte_left(galaxy_seed.f);
|
|
|
|
[universe setGalaxy_seed:galaxy_seed];
|
|
//system_seed = [universe findSystemAtCoords:NSMakePoint(0x60, 0x60) withGalaxySeed:galaxy_seed];
|
|
//
|
|
// instead find a system connected to system 0 near the current coordinates...
|
|
system_seed = [universe findConnectedSystemAtCoords:galaxy_coordinates withGalaxySeed:galaxy_seed];
|
|
//
|
|
target_system_seed = system_seed;
|
|
|
|
[universe setSystemTo:system_seed];
|
|
galaxy_coordinates.x = system_seed.d;
|
|
galaxy_coordinates.y = system_seed.b;
|
|
ranrot_srand([[NSDate date] timeIntervalSince1970]); // seed randomiser by time
|
|
market_rnd = ranrot_rand() & 255; // random factor for market values is reset
|
|
legal_status = 0;
|
|
[universe set_up_universe_from_witchspace];
|
|
}
|
|
|
|
- (void) enterWitchspaceWithEmergencyDrive
|
|
{
|
|
system_seed = [universe findNeighbouringSystemToCoords:galaxy_coordinates withGalaxySeed:galaxy_seed];
|
|
target_system_seed = system_seed;
|
|
|
|
status = STATUS_ENTERING_WITCHSPACE;
|
|
|
|
hyperspeed_engaged = NO;
|
|
|
|
[universe setDisplayText:NO];
|
|
[universe removeAllEntitiesExceptPlayer:NO];
|
|
|
|
[self remove_extra_equipment:@"EQ_EMERGENCY_HYPERDRIVE"];
|
|
fuel = 0; // use up all the fuel
|
|
|
|
[universe setSystemTo:target_system_seed];
|
|
system_seed = target_system_seed;
|
|
galaxy_coordinates.x = system_seed.d;
|
|
galaxy_coordinates.y = system_seed.b;
|
|
ranrot_srand([[NSDate date] timeIntervalSince1970]); // seed randomiser by time
|
|
market_rnd = ranrot_rand() & 255; // random factor for market values is reset
|
|
//
|
|
[universe set_up_universe_from_witchspace];
|
|
}
|
|
|
|
- (void) enterWitchspace
|
|
{
|
|
double distance = distanceBetweenPlanetPositions(target_system_seed.d,target_system_seed.b,galaxy_coordinates.x,galaxy_coordinates.y);
|
|
|
|
status = STATUS_ENTERING_WITCHSPACE;
|
|
|
|
hyperspeed_engaged = NO;
|
|
|
|
[universe setDisplayText:NO];
|
|
[universe removeAllEntitiesExceptPlayer:NO];
|
|
//
|
|
// reset the compass
|
|
//
|
|
if ([self has_extra_equipment:@"EQ_ADVANCED_COMPASS"])
|
|
compass_mode = COMPASS_MODE_PLANET;
|
|
else
|
|
compass_mode = COMPASS_MODE_BASIC;
|
|
//
|
|
// perform any check here for forced witchspace encounters
|
|
//
|
|
ranrot_srand([[NSDate date] timeIntervalSince1970]); // seed randomiser by time
|
|
BOOL misjump = ((flight_pitch == max_flight_pitch)||((ranrot_rand() & 0xff) > 253));
|
|
|
|
fuel -= 10.0 * distance; // fuel cost to target system
|
|
ship_clock_adjust = distance * distance * 3600.0; // LY * LY hrs
|
|
if (!misjump)
|
|
{
|
|
[universe setSystemTo:target_system_seed];
|
|
system_seed = target_system_seed;
|
|
galaxy_coordinates.x = system_seed.d;
|
|
galaxy_coordinates.y = system_seed.b;
|
|
legal_status /= 2; // 'another day, another system'
|
|
market_rnd = ranrot_rand() & 255; // random factor for market values is reset
|
|
if (market_rnd < 16)
|
|
[self erodeReputation]; // every 16 systems or so, drop back towards 'unknown'
|
|
//
|
|
if (market_rnd < ship_trade_in_factor) // every four jumps or so
|
|
ship_trade_in_factor -= 1 + (market_rnd & 3); // drop the price down towards 75%
|
|
if (ship_trade_in_factor < 75)
|
|
ship_trade_in_factor = 75; // lower limit for trade in value is 75%
|
|
//
|
|
[universe set_up_universe_from_witchspace];
|
|
[[universe planet] update: 2.34375 * market_rnd]; // from 0..10 minutes
|
|
[[universe station] update: 2.34375 * market_rnd]; // from 0..10 minutes
|
|
}
|
|
else
|
|
{
|
|
//NSLog(@"---> Witchspace misjump");
|
|
// move sort of halfway there...
|
|
galaxy_coordinates.x += target_system_seed.d;
|
|
galaxy_coordinates.y += target_system_seed.b;
|
|
galaxy_coordinates.x /= 2;
|
|
galaxy_coordinates.y /= 2;
|
|
#ifdef HAVE_SOUND
|
|
[ecmSound play];
|
|
#endif
|
|
[universe set_up_universe_from_misjump];
|
|
}
|
|
}
|
|
|
|
- (void) leaveWitchspace
|
|
{
|
|
Vector pos = [universe getWitchspaceExitPosition];
|
|
Quaternion q_rtn = [universe getWitchspaceExitRotation];
|
|
Quaternion q1;
|
|
|
|
quaternion_set_random(&q1);
|
|
double d1 = SCANNER_MAX_RANGE*((ranrot_rand() % 256)/256.0 - 0.5);
|
|
if (abs(d1) < 500.0) // no closer than 500m
|
|
d1 += ((d1 > 0.0)? 500.0: -500.0);
|
|
Vector v1 = vector_forward_from_quaternion(q1);
|
|
pos.x += v1.x * d1; // randomise exit position
|
|
pos.y += v1.y * d1;
|
|
pos.z += v1.z * d1;
|
|
|
|
position = pos;
|
|
q_rotation = q_rtn;
|
|
flight_roll = 0.0;
|
|
flight_pitch = 0.0;
|
|
flight_speed = max_flight_speed * 0.25;
|
|
status = STATUS_EXITING_WITCHSPACE;
|
|
gui_screen = GUI_SCREEN_MAIN;
|
|
being_fined = NO; // until you're scanned by a copper!
|
|
[self setShowDemoShips:NO];
|
|
[universe setDisplayCursor:NO];
|
|
[universe setDisplayText:NO];
|
|
[universe set_up_break_pattern:position quaternion:q_rotation];
|
|
#ifdef HAVE_SOUND
|
|
[breakPatternSound play];
|
|
#endif
|
|
}
|
|
|
|
- (void) performDocking
|
|
{
|
|
[self abortDocking]; // let the station know that you are no longer on approach
|
|
autopilot_engaged = NO;
|
|
status = STATUS_IN_FLIGHT;
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
|
|
- (void) quicksavePlayer
|
|
{
|
|
NSString* filename = [[(MyOpenGLView *)[universe gameView] gameController] playerFileToLoad];
|
|
if (!filename)
|
|
{
|
|
NSBeep();
|
|
NSLog(@"ERROR no filename returned by [[(MyOpenGLView *)[universe gameView] gameController] playerFileToLoad]");
|
|
NSException* myException = [NSException
|
|
exceptionWithName:@"GameNotSavedException"
|
|
reason:@"ERROR no filename returned by [[(MyOpenGLView *)[universe gameView] gameController] playerFileToLoad]"
|
|
userInfo:nil];
|
|
[myException raise];
|
|
return;
|
|
}
|
|
if (![[self commanderDataDictionary] writeToFile:filename atomically:YES])
|
|
{
|
|
NSBeep();
|
|
NSLog(@"***** ERROR: Save to %@ failed!", filename);
|
|
NSException* myException = [NSException
|
|
exceptionWithName:@"GameNotSavedException"
|
|
reason:[NSString stringWithFormat:@"Attempt to save game to file '%@' failed for some reason", filename]
|
|
userInfo:nil];
|
|
[myException raise];
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
[universe clearPreviousMessage]; // allow this to be given time and again
|
|
[universe addMessage:[universe expandDescription:@"[game-saved]" forSystem:system_seed] forCount:2];
|
|
}
|
|
[self setGuiToStatusScreen];
|
|
}
|
|
|
|
- (void) savePlayer
|
|
{
|
|
NSSavePanel *sp;
|
|
int runResult;
|
|
|
|
/* create or get the shared instance of NSSavePanel */
|
|
sp = [NSSavePanel savePanel];
|
|
|
|
/* set up new attributes */
|
|
[sp setRequiredFileType:@"oolite-save"];
|
|
|
|
/* display the NSSavePanel */
|
|
|
|
runResult = [sp runModalForDirectory:nil file:player_name];
|
|
|
|
/* if successful, save file under designated name */
|
|
if (runResult == NSOKButton)
|
|
{
|
|
NSArray* path_components = [[sp filename] pathComponents];
|
|
NSString* new_name = [[path_components objectAtIndex:[path_components count]-1] stringByDeletingPathExtension];
|
|
|
|
//NSLog(@"Attempting to save to %@",[sp filename]);
|
|
//NSLog(@"Will set Commander's name to %@", new_name);
|
|
|
|
if (player_name) [player_name release];
|
|
player_name = [new_name retain];
|
|
|
|
if (![[self commanderDataDictionary] writeToFile:[sp filename] atomically:YES])
|
|
{
|
|
NSBeep();
|
|
NSLog(@"***** ERROR: Save to %@ failed!", [sp filename]);
|
|
NSException* myException = [NSException
|
|
exceptionWithName:@"GameNotSavedException"
|
|
reason:[NSString stringWithFormat:@"Attempt to save game to file '%@' failed for some reason", [sp filename]]
|
|
userInfo:nil];
|
|
[myException raise];
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
[[(MyOpenGLView *)[universe gameView] gameController] setPlayerFileToLoad:[sp filename]];
|
|
}
|
|
}
|
|
[self setGuiToStatusScreen];
|
|
}
|
|
|
|
- (void) loadPlayer
|
|
{
|
|
int result;
|
|
NSArray *fileTypes = [NSArray arrayWithObject:@"oolite-save"];
|
|
NSOpenPanel *oPanel = [NSOpenPanel openPanel];
|
|
|
|
[oPanel setAllowsMultipleSelection:NO];
|
|
result = [oPanel runModalForDirectory:nil file:nil types:fileTypes];
|
|
if (result == NSOKButton)
|
|
[self loadPlayerFromFile:[oPanel filename]];
|
|
}
|
|
|
|
- (void) loadPlayerFromFile:(NSString *)fileToOpen
|
|
{
|
|
BOOL loadedOK = NO;
|
|
NSDictionary *fileDic = nil;
|
|
if (fileToOpen)
|
|
{
|
|
fileDic = [NSDictionary dictionaryWithContentsOfFile:fileToOpen];
|
|
if (fileDic)
|
|
{
|
|
[self set_up];
|
|
[self setCommanderDataFromDictionary:fileDic];
|
|
loadedOK = YES;
|
|
}
|
|
}
|
|
if (!loadedOK)
|
|
NSBeep();
|
|
else
|
|
{
|
|
[[(MyOpenGLView *)[universe gameView] gameController] setPlayerFileToLoad:fileToOpen];
|
|
}
|
|
|
|
[universe setSystemTo:system_seed];
|
|
[universe removeAllEntitiesExceptPlayer:NO];
|
|
[universe set_up_space];
|
|
|
|
status = STATUS_DOCKED;
|
|
[universe setViewDirection:VIEW_DOCKED];
|
|
|
|
docked_station = [universe station];
|
|
if (docked_station)
|
|
{
|
|
position = docked_station->position;
|
|
[self setQRotation:docked_station->q_rotation];
|
|
v_forward = vector_forward_from_quaternion(q_rotation);
|
|
v_right = vector_right_from_quaternion(q_rotation);
|
|
v_up = vector_up_from_quaternion(q_rotation);
|
|
|
|
q_rotation.w = -q_rotation.w; // need this as a fix...
|
|
}
|
|
|
|
flight_roll = 0.0;
|
|
flight_pitch = 0.0;
|
|
flight_speed = 0.0;
|
|
|
|
if (![docked_station localMarket])
|
|
{
|
|
if ([fileDic objectForKey:@"localMarket"])
|
|
{
|
|
[docked_station setLocalMarket:(NSArray *)[fileDic objectForKey:@"localMarket"]];
|
|
}
|
|
else
|
|
{
|
|
[docked_station initialiseLocalMarketWithSeed:system_seed andRandomFactor:market_rnd];
|
|
}
|
|
}
|
|
[self setGuiToStatusScreen];
|
|
}
|
|
|
|
- (void) changePlayerName
|
|
{
|
|
}
|
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
- (void) setGuiToStatusScreen
|
|
{
|
|
NSDictionary* descriptions = [universe descriptions];
|
|
NSString* systemName;
|
|
NSString* targetSystemName;
|
|
|
|
//NSLog(@"DEBUG original hold size = %d",original_hold_size);
|
|
|
|
system_seed = [universe findSystemAtCoords:galaxy_coordinates withGalaxySeed:galaxy_seed];
|
|
target_system_seed = [universe findSystemAtCoords:cursor_coordinates withGalaxySeed:galaxy_seed];
|
|
|
|
systemName = [universe getSystemName:system_seed];
|
|
if (status == STATUS_DOCKED)
|
|
{
|
|
if ((docked_station != [universe station])&&(docked_station != nil))
|
|
systemName = [NSString stringWithFormat:@"%@ : %@", systemName, [(ShipEntity*)docked_station name]];
|
|
}
|
|
|
|
targetSystemName = [universe getSystemName:target_system_seed];
|
|
|
|
// GUI stuff
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
int equip_row = 10;
|
|
int tab_stops[GUI_MAX_COLUMNS];
|
|
tab_stops[0] = 20;
|
|
tab_stops[1] = 160;
|
|
tab_stops[2] = 256;
|
|
[gui setTabStops:tab_stops];
|
|
|
|
NSArray* gear = [self equipmentList];
|
|
|
|
int legal_index = 0;
|
|
if (legal_status != 0)
|
|
legal_index = (legal_status <= 50) ? 1 : 2;
|
|
int rating = 0;
|
|
int kills[8] = { 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0200, 0x0A00, 0x1900 };
|
|
while ((rating < 8)&&(kills[rating] <= ship_kills))
|
|
{
|
|
rating ++;
|
|
}
|
|
|
|
NSDictionary *ship_dict = [universe getDictionaryForShip:ship_desc];
|
|
NSString* shipName = (NSString*)[ship_dict objectForKey:KEY_NAME];
|
|
|
|
NSString* legal_desc = (NSString *)[(NSArray *)[descriptions objectForKey:@"legal_status"] objectAtIndex:legal_index];
|
|
// NSString* rating_desc = (NSString *)[(NSArray *)[descriptions objectForKey:@"rating"] objectAtIndex:rating];
|
|
NSString* rating_desc = [NSString stringWithFormat:@"%@ (%d)",[(NSArray *)[descriptions objectForKey:@"rating"] objectAtIndex:rating], ship_kills];
|
|
NSString* alert_desc = (NSString *)[(NSArray *)[descriptions objectForKey:@"condition"] objectAtIndex:[self alert_condition]];
|
|
[gui clear];
|
|
[gui setTitle:[NSString stringWithFormat:@"Commander %@", player_name]];
|
|
//
|
|
[gui setText:shipName forRow:0 align:GUI_ALIGN_CENTER];
|
|
//
|
|
[gui setArray:[NSArray arrayWithObjects:@"Present System:", systemName, nil] forRow:1];
|
|
[gui setArray:[NSArray arrayWithObjects:@"Hyperspace System:", targetSystemName, nil] forRow:2];
|
|
[gui setArray:[NSArray arrayWithObjects:@"Condition:", alert_desc, nil] forRow:3];
|
|
[gui setArray:[NSArray arrayWithObjects:@"Fuel:", [NSString stringWithFormat:@"%.1f Light Years", fuel/10.0], nil] forRow:4];
|
|
[gui setArray:[NSArray arrayWithObjects:@"Cash:", [NSString stringWithFormat:@"%.1f Cr", credits/10.0], nil] forRow:5];
|
|
[gui setArray:[NSArray arrayWithObjects:@"Legal Status:", legal_desc, nil] forRow:6];
|
|
[gui setArray:[NSArray arrayWithObjects:@"Rating:", rating_desc, nil] forRow:7];
|
|
//
|
|
[gui setText:@"Equipment:" forRow:9];
|
|
|
|
int i = 0;
|
|
int n_equip_rows = 5;
|
|
while ([gear count] > n_equip_rows * 2) // make room for larger numbers of items
|
|
n_equip_rows++; // by extending the length of the two columns
|
|
for (i = 0; i < n_equip_rows; i++)
|
|
{
|
|
NSMutableArray* row_info = [NSMutableArray arrayWithCapacity:3];
|
|
if (i < [gear count])
|
|
[row_info addObject:[gear objectAtIndex:i]];
|
|
else
|
|
[row_info addObject:@""];
|
|
|
|
// add a blank
|
|
[row_info addObject:@""];
|
|
|
|
if (i + n_equip_rows < [gear count])
|
|
[row_info addObject:[gear objectAtIndex:i + n_equip_rows]];
|
|
else
|
|
[row_info addObject:@""];
|
|
[gui setArray:(NSArray *)row_info forRow:equip_row + i];
|
|
}
|
|
|
|
|
|
[gui setShowTextCursor:NO];
|
|
|
|
// [gui generateDisplay];
|
|
[universe guiUpdated];
|
|
}
|
|
/* ends */
|
|
|
|
//NSLog(@"gui_screen = GUI_SCREEN_STATUS");
|
|
if (lastTextKey)
|
|
{
|
|
[lastTextKey release];
|
|
lastTextKey = nil;
|
|
}
|
|
|
|
[self setShowDemoShips:NO];
|
|
gui_screen = GUI_SCREEN_STATUS;
|
|
}
|
|
|
|
- (NSArray *) equipmentList
|
|
{
|
|
NSDictionary* descriptions = [universe descriptions];
|
|
//int original_hold_size = [universe maxCargoForShip:ship_desc];
|
|
NSMutableArray* quip = [NSMutableArray arrayWithCapacity:32];
|
|
//
|
|
int i;
|
|
NSArray* equipmentinfo = [universe equipmentdata];
|
|
for (i =0; i < [equipmentinfo count]; i++)
|
|
{
|
|
NSString *w_key = (NSString *)[(NSArray *)[equipmentinfo objectAtIndex:i] objectAtIndex:EQUIPMENT_KEY_INDEX];
|
|
if ([self has_extra_equipment:w_key])
|
|
[quip addObject:(NSString *)[(NSArray *)[equipmentinfo objectAtIndex:i] objectAtIndex:EQUIPMENT_SHORT_DESC_INDEX]];
|
|
}
|
|
|
|
if (forward_weapon > 0)
|
|
[quip addObject:[NSString stringWithFormat:@"Forward %@",(NSString *)[(NSArray *)[descriptions objectForKey:@"weapon_name"] objectAtIndex:forward_weapon]]];
|
|
if (aft_weapon > 0)
|
|
[quip addObject:[NSString stringWithFormat:@"Aft %@",(NSString *)[(NSArray *)[descriptions objectForKey:@"weapon_name"] objectAtIndex:aft_weapon]]];
|
|
if (starboard_weapon > 0)
|
|
[quip addObject:[NSString stringWithFormat:@"Starboard %@",(NSString *)[(NSArray *)[descriptions objectForKey:@"weapon_name"] objectAtIndex:starboard_weapon]]];
|
|
if (port_weapon > 0)
|
|
[quip addObject:[NSString stringWithFormat:@"Port %@",(NSString *)[(NSArray *)[descriptions objectForKey:@"weapon_name"] objectAtIndex:port_weapon]]];
|
|
|
|
if (max_passengers > 0)
|
|
[quip addObject:[NSString stringWithFormat:@"%d Passenger Berth%@", max_passengers, (max_passengers > 1)? @"s" : @""]];
|
|
|
|
return [NSArray arrayWithArray:quip];
|
|
}
|
|
|
|
- (NSArray *) cargoList
|
|
{
|
|
NSMutableArray* manifest = [NSMutableArray arrayWithCapacity:32];
|
|
//
|
|
// NSLog(@"DEBUG ::::: %@", [shipCommodityData description]);
|
|
|
|
if (specialCargo)
|
|
[manifest addObject:specialCargo];
|
|
|
|
int n_commodities = [shipCommodityData count];
|
|
int in_hold[n_commodities];
|
|
int i;
|
|
//
|
|
if (status == STATUS_DOCKED)
|
|
{
|
|
for (i = 0; i < n_commodities; i++)
|
|
in_hold[i] = [(NSNumber *)[(NSArray *)[shipCommodityData objectAtIndex:i] objectAtIndex:MARKET_QUANTITY] intValue];
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < n_commodities; i++)
|
|
in_hold[i] = 0;
|
|
for (i = 0; i < [cargo count]; i++)
|
|
{
|
|
ShipEntity *container = (ShipEntity *)[cargo objectAtIndex:i];
|
|
in_hold[[container getCommodityType]] += [container getCommodityAmount];
|
|
}
|
|
}
|
|
//
|
|
for (i = 0; i < n_commodities; i++)
|
|
{
|
|
if (in_hold[i] > 0)
|
|
{
|
|
int unit = [universe unitsForCommodity:i];
|
|
NSString* units = @"t";
|
|
if (unit == UNITS_KILOGRAMS) units = @"kg";
|
|
if (unit == UNITS_GRAMS) units = @"g";
|
|
NSString* desc = (NSString *)[(NSArray *)[shipCommodityData objectAtIndex:i] objectAtIndex:MARKET_NAME];
|
|
[manifest addObject:[NSString stringWithFormat:@"%d%@ x %@", in_hold[i], units, desc]];
|
|
}
|
|
}
|
|
|
|
// // debug
|
|
// NSLog(@"DEBUG shipCommodityData:-\n%@", [shipCommodityData description]);
|
|
// NSLog(@"DEBUG manifest:-\n%@", [manifest description]);
|
|
|
|
//
|
|
return [NSArray arrayWithArray:manifest];
|
|
}
|
|
|
|
- (void) setGuiToSystemDataScreen
|
|
{
|
|
NSDictionary* targetSystemData;
|
|
NSString* targetSystemName;
|
|
NSDictionary* descriptions = [universe descriptions];
|
|
|
|
target_system_seed = [universe findSystemAtCoords:cursor_coordinates withGalaxySeed:galaxy_seed];
|
|
|
|
targetSystemData = [[universe generateSystemData:target_system_seed] retain]; // retained
|
|
targetSystemName = [[universe getSystemName:target_system_seed] retain]; // retained
|
|
|
|
BOOL sun_gone_nova = NO;
|
|
if ([targetSystemData objectForKey:@"sun_gone_nova"])
|
|
sun_gone_nova = YES;
|
|
|
|
// GUI stuff
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
|
|
int tab_stops[GUI_MAX_COLUMNS];
|
|
tab_stops[0] = 0;
|
|
tab_stops[1] = 96;
|
|
tab_stops[2] = 144;
|
|
[gui setTabStops:tab_stops];
|
|
|
|
int government = [(NSNumber *)[targetSystemData objectForKey:KEY_GOVERNMENT] intValue];
|
|
int economy = [(NSNumber *)[targetSystemData objectForKey:KEY_ECONOMY] intValue];
|
|
int techlevel = [(NSNumber *)[targetSystemData objectForKey:KEY_TECHLEVEL] intValue];
|
|
int population = [(NSNumber *)[targetSystemData objectForKey:KEY_POPULATION] intValue];
|
|
int productivity = [(NSNumber *)[targetSystemData objectForKey:KEY_PRODUCTIVITY] intValue];
|
|
int radius = [(NSNumber *)[targetSystemData objectForKey:KEY_RADIUS] intValue];
|
|
|
|
NSString* government_desc = (NSString *)[(NSArray *)[descriptions objectForKey:KEY_GOVERNMENT] objectAtIndex:government];
|
|
NSString* economy_desc = (NSString *)[(NSArray *)[descriptions objectForKey:KEY_ECONOMY] objectAtIndex:economy];
|
|
NSString* inhabitants = (NSString *)[targetSystemData objectForKey:KEY_INHABITANTS];
|
|
NSString* system_desc = (NSString *)[targetSystemData objectForKey:KEY_DESCRIPTION];
|
|
|
|
if ((sun_gone_nova && equal_seeds( target_system_seed, system_seed) && [[universe sun] goneNova])||
|
|
(sun_gone_nova && (!equal_seeds( target_system_seed, system_seed))))
|
|
{
|
|
population = 0;
|
|
productivity = 0;
|
|
radius = 0;
|
|
system_desc = [universe expandDescription:@"[nova-system-description]" forSystem:target_system_seed];
|
|
}
|
|
|
|
[gui clear];
|
|
[gui setTitle:[NSString stringWithFormat:@"Data on %@", targetSystemName]];
|
|
//
|
|
[gui setArray:[NSArray arrayWithObjects:@"Economy:", economy_desc, nil] forRow:1];
|
|
//
|
|
[gui setArray:[NSArray arrayWithObjects:@"Government:", government_desc, nil] forRow:3];
|
|
//
|
|
[gui setArray:[NSArray arrayWithObjects:@"Tech Level:", [NSString stringWithFormat:@"%d", techlevel + 1], nil] forRow:5];
|
|
//
|
|
[gui setArray:[NSArray arrayWithObjects:@"Population:", [NSString stringWithFormat:@"%.1f Billion", 0.1*population], nil] forRow:7];
|
|
[gui setArray:[NSArray arrayWithObjects:@"", [NSString stringWithFormat:@"(%@)", inhabitants], nil] forRow:8];
|
|
//
|
|
[gui setArray:[NSArray arrayWithObjects:@"Gross Productivity:", @"", [NSString stringWithFormat:@"%5d M Cr.", productivity], nil] forRow:10];
|
|
//
|
|
[gui setArray:[NSArray arrayWithObjects:@"Average radius:", @"", [NSString stringWithFormat:@"%5d km", radius], nil] forRow:12];
|
|
//
|
|
int i = [gui addLongText:system_desc startingAtRow:15 align:GUI_ALIGN_LEFT];
|
|
missionTextRow = i;
|
|
for (i-- ; i > 14 ; i--)
|
|
[gui setColor:[NSColor greenColor] forRow:i];
|
|
//
|
|
|
|
[gui setShowTextCursor:NO];
|
|
|
|
[universe guiUpdated];
|
|
}
|
|
/* ends */
|
|
|
|
//NSLog(@"gui_screen = GUI_SCREEN_SYSTEM_DATA for system %@ at (%d,%d)",targetSystemName,target_system_seed.d,target_system_seed.b);
|
|
|
|
[self setShowDemoShips:NO];
|
|
gui_screen = GUI_SCREEN_SYSTEM_DATA;
|
|
|
|
if (lastTextKey)
|
|
{
|
|
[lastTextKey release];
|
|
lastTextKey = nil;
|
|
}
|
|
|
|
[targetSystemData release]; // released
|
|
[targetSystemName release]; // released
|
|
}
|
|
|
|
- (NSArray *) markedDestinations
|
|
{
|
|
NSMutableArray* destinations = [NSMutableArray arrayWithCapacity:256];
|
|
// get a list of systems marked as contract destinations
|
|
BOOL mark[256];
|
|
int i;
|
|
for (i = 0; i < 256; i++)
|
|
mark[i] = NO;
|
|
for (i = 0; i < [passengers count]; i++)
|
|
mark[[(NSNumber*)[(NSDictionary*)[passengers objectAtIndex:i] objectForKey:PASSENGER_KEY_DESTINATION] intValue]] = YES;
|
|
for (i = 0; i < [contracts count]; i++)
|
|
mark[[(NSNumber*)[(NSDictionary*)[contracts objectAtIndex:i] objectForKey:CONTRACT_KEY_DESTINATION] intValue]] = YES;
|
|
for (i = 0; i < 256; i++)
|
|
[destinations addObject:[NSNumber numberWithBool:mark[i]]];
|
|
|
|
return destinations;
|
|
}
|
|
|
|
- (void) setGuiToLongRangeChartScreen
|
|
{
|
|
NSString* targetSystemName;
|
|
double distance = distanceBetweenPlanetPositions(target_system_seed.d,target_system_seed.b,galaxy_coordinates.x,galaxy_coordinates.y);
|
|
int i;
|
|
|
|
target_system_seed = [universe findSystemAtCoords:cursor_coordinates withGalaxySeed:galaxy_seed];
|
|
targetSystemName = [[universe getSystemName:target_system_seed] retain]; // retained
|
|
|
|
// get a list of systems marked as contract destinations
|
|
BOOL mark[256];
|
|
for (i = 0; i < 256; i++)
|
|
mark[i] = NO;
|
|
for (i = 0; i < [passengers count]; i++)
|
|
mark[[(NSNumber*)[(NSDictionary*)[passengers objectAtIndex:i] objectForKey:PASSENGER_KEY_DESTINATION] intValue]] = YES;
|
|
for (i = 0; i < [contracts count]; i++)
|
|
mark[[(NSNumber*)[(NSDictionary*)[contracts objectAtIndex:i] objectForKey:CONTRACT_KEY_DESTINATION] intValue]] = YES;
|
|
|
|
// GUI stuff
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
|
|
[gui clear];
|
|
[gui setTitle:[NSString stringWithFormat:@"Galactic Chart %d", galaxy_number+1]];
|
|
//
|
|
[gui setText:targetSystemName forRow:17];
|
|
[gui setText:[NSString stringWithFormat:@"Distance:\t%.1f Light Years", distance] forRow:18];
|
|
//
|
|
if (planetSearchString)
|
|
[gui setText:[NSString stringWithFormat:@"Find planet: %@", [planetSearchString capitalizedString]] forRow:16];
|
|
else
|
|
[gui setText:@"Find planet: " forRow:16];
|
|
[gui setColor:[NSColor cyanColor] forRow:16];
|
|
|
|
[gui setShowTextCursor:YES];
|
|
[gui setCurrentRow:16];
|
|
|
|
//
|
|
[universe guiUpdated];
|
|
}
|
|
/* ends */
|
|
|
|
//NSLog(@"gui_screen = GUI_SCREEN_LONG_RANGE_CHART");
|
|
|
|
[self setShowDemoShips:NO];
|
|
gui_screen = GUI_SCREEN_LONG_RANGE_CHART;
|
|
|
|
[targetSystemName release]; // released
|
|
}
|
|
|
|
- (void) starChartDump
|
|
{
|
|
NSString *filepath = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent];
|
|
NSString *pathToPic = [filepath stringByAppendingPathComponent:[NSString stringWithFormat:@"StarChart-Galaxy-%03d.tiff",galaxy_number]];
|
|
BOOL dumpPic = (![[NSFileManager defaultManager] fileExistsAtPath:pathToPic]);
|
|
NSString *pathToData = [filepath stringByAppendingPathComponent:[NSString stringWithFormat:@"StarChartData-Galaxy-%03d.txt",galaxy_number]];
|
|
BOOL dumpData = (![[NSFileManager defaultManager] fileExistsAtPath:pathToData]);
|
|
|
|
NSString* targetSystemName;
|
|
Random_Seed g_seed = galaxy_seed;
|
|
|
|
target_system_seed = [universe findSystemAtCoords:cursor_coordinates withGalaxySeed:galaxy_seed];
|
|
targetSystemName = [[universe getSystemName:target_system_seed] retain]; // retained
|
|
|
|
int star_x[256];
|
|
int star_y[256];
|
|
|
|
NSPoint nudge[256];
|
|
|
|
NSMutableString *stardump = [NSMutableString stringWithString:@"\nStar List\n"];
|
|
g_seed = galaxy_seed;
|
|
int i;
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
NSDictionary* systemDataDic = [universe generateSystemData:g_seed];
|
|
int government = [(NSNumber *)[systemDataDic objectForKey:KEY_GOVERNMENT] intValue];
|
|
int techlevel = [(NSNumber *)[systemDataDic objectForKey:KEY_TECHLEVEL] intValue];
|
|
NSString* government_desc = (NSString *)[(NSArray *)[[universe descriptions] objectForKey:KEY_GOVERNMENT] objectAtIndex:government];
|
|
NSString* inhabitants = (NSString *)[systemDataDic objectForKey:KEY_INHABITANTS];
|
|
NSString* system_desc = (NSString *)[systemDataDic objectForKey:KEY_DESCRIPTION];
|
|
|
|
star_x[i] = g_seed.d;
|
|
star_y[i] = g_seed.b;
|
|
|
|
nudge[i] = NSMakePoint(0.0,0.0);
|
|
|
|
[stardump appendFormat:@"System %d,\t%@\t(%d,%d)\tTL: %d\t%@\t%@\n\t\"%@\"\n", i, [universe getSystemName:g_seed], g_seed.d, g_seed.b, techlevel, inhabitants, government_desc, system_desc];
|
|
rotate_seed(&g_seed);
|
|
rotate_seed(&g_seed);
|
|
rotate_seed(&g_seed);
|
|
rotate_seed(&g_seed);
|
|
}
|
|
if (dumpData)
|
|
[stardump writeToFile:pathToData atomically:YES];
|
|
|
|
|
|
// drawing stuff
|
|
if (dumpPic)
|
|
{
|
|
NSMutableDictionary *textAttributes = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
|
[NSFont systemFontOfSize:9.0], NSFontAttributeName,
|
|
[NSColor blueColor], NSForegroundColorAttributeName, NULL];
|
|
|
|
NSSize imageSize = NSMakeSize(1088,576);
|
|
NSSize chartSize = NSMakeSize(1024,512);
|
|
|
|
NSImage* drawImage = [[NSImage alloc] initWithSize:imageSize];
|
|
|
|
NSPoint star;
|
|
|
|
g_seed = galaxy_seed;
|
|
double hscale = chartSize.width / 256.0;
|
|
double vscale = chartSize.height / 256.0;
|
|
double hoffset = (imageSize.width - chartSize.width) / 2.0;
|
|
double voffset = (imageSize.height - chartSize.height) / 2.0;
|
|
|
|
[drawImage lockFocus];
|
|
|
|
[[NSColor darkGrayColor] set];
|
|
NSRectFill(NSMakeRect(0.0,0.0,imageSize.width,imageSize.height));
|
|
|
|
[[NSColor grayColor] set];
|
|
[NSBezierPath setDefaultLineCapStyle:NSRoundLineCapStyle];
|
|
[NSBezierPath setDefaultLineWidth:36.0];
|
|
//draw connectivity map
|
|
int j;
|
|
for (i = 0; i < 256; i++) for (j = i + 1; j < 256; j++)
|
|
{
|
|
double d = distanceBetweenPlanetPositions(star_x[i],star_y[i],star_x[j],star_y[j]);
|
|
|
|
if (d <= 7.0)
|
|
{
|
|
NSPoint p1 = NSMakePoint(star_x[i] * hscale + hoffset,(256 - star_y[i]) * vscale + voffset);
|
|
NSPoint p2 = NSMakePoint(star_x[j] * hscale + hoffset,(256 - star_y[j]) * vscale + voffset);
|
|
|
|
nudge[i].x += (d != 0.0) ? hscale * (star_x[i] - star_x[j])/(d*d*4.0) : 10.0;
|
|
nudge[i].y += (d != 0.0) ? vscale * (star_y[i] - star_y[j])/(d*d*4.0) : 10.0;
|
|
nudge[j].x -= (d != 0.0) ? hscale * (star_x[i] - star_x[j])/(d*d*4.0) : 10.0;
|
|
nudge[j].y -= (d != 0.0) ? vscale * (star_y[i] - star_y[j])/(d*d*4.0) : 10.0;
|
|
|
|
[NSBezierPath strokeLineFromPoint:p1 toPoint:p2];
|
|
|
|
}
|
|
}
|
|
|
|
[[NSColor lightGrayColor] set];
|
|
[NSBezierPath setDefaultLineCapStyle:NSRoundLineCapStyle];
|
|
[NSBezierPath setDefaultLineWidth:32.0];
|
|
//draw connectivity map
|
|
for (i = 0; i < 256; i++) for (j = i + 1; j < 256; j++)
|
|
{
|
|
double d = distanceBetweenPlanetPositions(star_x[i],star_y[i],star_x[j],star_y[j]);
|
|
|
|
if (d <= 7.0)
|
|
{
|
|
NSPoint p1 = NSMakePoint(star_x[i] * hscale + hoffset,(256 - star_y[i]) * vscale + voffset);
|
|
NSPoint p2 = NSMakePoint(star_x[j] * hscale + hoffset,(256 - star_y[j]) * vscale + voffset);
|
|
|
|
[NSBezierPath strokeLineFromPoint:p1 toPoint:p2];
|
|
|
|
}
|
|
}
|
|
|
|
[[NSColor whiteColor] set];
|
|
[NSBezierPath setDefaultLineCapStyle:NSRoundLineCapStyle];
|
|
[NSBezierPath setDefaultLineWidth:28.0];
|
|
//draw connectivity map
|
|
for (i = 0; i < 256; i++) for (j = i + 1; j < 256; j++)
|
|
{
|
|
double d = distanceBetweenPlanetPositions(star_x[i],star_y[i],star_x[j],star_y[j]);
|
|
|
|
if (d <= 7.0)
|
|
{
|
|
NSPoint p1 = NSMakePoint(star_x[i] * hscale + hoffset,(256 - star_y[i]) * vscale + voffset);
|
|
NSPoint p2 = NSMakePoint(star_x[j] * hscale + hoffset,(256 - star_y[j]) * vscale + voffset);
|
|
|
|
[NSBezierPath strokeLineFromPoint:p1 toPoint:p2];
|
|
|
|
}
|
|
}
|
|
|
|
[[NSColor yellowColor] set];
|
|
[NSBezierPath setDefaultLineCapStyle:NSRoundLineCapStyle];
|
|
[NSBezierPath setDefaultLineWidth:4.0];
|
|
//draw connectivity map
|
|
for (i = 0; i < 256; i++) for (j = i + 1; j < 256; j++)
|
|
{
|
|
double d = distanceBetweenPlanetPositions(star_x[i],star_y[i],star_x[j],star_y[j]);
|
|
|
|
if (d <= 7.0)
|
|
{
|
|
NSPoint p1 = NSMakePoint(star_x[i] * hscale + hoffset,(256 - star_y[i]) * vscale + voffset);
|
|
NSPoint p2 = NSMakePoint(star_x[j] * hscale + hoffset,(256 - star_y[j]) * vscale + voffset);
|
|
|
|
[NSBezierPath strokeLineFromPoint:p1 toPoint:p2];
|
|
|
|
}
|
|
}
|
|
|
|
g_seed = galaxy_seed; // keep for sizing!
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
double sz = ((g_seed.e | 0x50) < 0x90) ? 1.0 : 1.5;
|
|
star.x = star_x[i] * hscale + hoffset;
|
|
star.y = (256 - star_y[i]) * vscale + voffset;
|
|
|
|
if (nudge[i].x*nudge[i].x > 100.0)
|
|
nudge[i].x = (nudge[i].x < 0.0) ? -10.0 : 10.0;
|
|
if (nudge[i].y*nudge[i].y > 100.0)
|
|
nudge[i].y = (nudge[i].y < 0.0) ? -10.0 : 10.0;
|
|
|
|
[[NSColor blackColor] set];
|
|
[[NSBezierPath bezierPathWithOvalInRect:NSMakeRect(star.x - sz, star.y - sz, sz * 2.0, sz * 2.0)] fill];
|
|
|
|
[[NSString stringWithFormat:@"%d",i] drawAtPoint:NSMakePoint(star.x + 1.0 + nudge[i].x, star.y - 4.5 - nudge[i].y) withAttributes:textAttributes];
|
|
|
|
rotate_seed(&g_seed);
|
|
rotate_seed(&g_seed);
|
|
rotate_seed(&g_seed);
|
|
rotate_seed(&g_seed);
|
|
}
|
|
|
|
//
|
|
[drawImage unlockFocus];
|
|
// write to file
|
|
[[drawImage TIFFRepresentation] writeToFile:pathToPic atomically:YES];
|
|
//
|
|
[drawImage release];
|
|
[NSBezierPath setDefaultLineCapStyle:NSRoundLineCapStyle];
|
|
[NSBezierPath setDefaultLineWidth:1.0];
|
|
}
|
|
/* ends */
|
|
}
|
|
|
|
|
|
- (void) setGuiToShortRangeChartScreen
|
|
{
|
|
NSString* targetSystemName;
|
|
double distance = distanceBetweenPlanetPositions(target_system_seed.d,target_system_seed.b,galaxy_coordinates.x,galaxy_coordinates.y);
|
|
|
|
target_system_seed = [universe findSystemAtCoords:cursor_coordinates withGalaxySeed:galaxy_seed];
|
|
targetSystemName = [[universe getSystemName:target_system_seed] retain]; // retained
|
|
|
|
//NSLog(@"found %@ at (%d, %d)",targetSystemName,(int)cursor_coordinates.x,(int)cursor_coordinates.y);
|
|
|
|
// GUI stuff
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
|
|
if ((abs(cursor_coordinates.x-galaxy_coordinates.x)>=20)||(abs(cursor_coordinates.y-galaxy_coordinates.y)>=38))
|
|
cursor_coordinates = galaxy_coordinates; // home
|
|
|
|
[gui clear];
|
|
[gui setTitle:@"Short Range Chart"];
|
|
//
|
|
[gui setText:targetSystemName forRow:19];
|
|
[gui setText:[NSString stringWithFormat:@"Distance:\t%.1f Light Years", distance] forRow:20];
|
|
//
|
|
|
|
[gui setShowTextCursor:NO];
|
|
|
|
[universe guiUpdated];
|
|
}
|
|
/* ends */
|
|
|
|
//NSLog(@"gui_screen = GUI_SCREEN_LONG_RANGE_CHART");
|
|
|
|
[self setShowDemoShips:NO];
|
|
gui_screen = GUI_SCREEN_SHORT_RANGE_CHART;
|
|
|
|
[targetSystemName release]; // released
|
|
}
|
|
|
|
- (void) setGuiToLoadSaveScreen
|
|
{
|
|
BOOL canLoadOrSave = NO;
|
|
if (status == STATUS_DOCKED)
|
|
{
|
|
if (!docked_station)
|
|
docked_station = [universe station];
|
|
canLoadOrSave = (docked_station == [universe station]);
|
|
}
|
|
BOOL canQuickSave = (canLoadOrSave && ([[(MyOpenGLView *)[universe gameView] gameController] playerFileToLoad] != nil));
|
|
|
|
GameController *controller = [universe gameController];
|
|
#ifndef GNUSTEP
|
|
int displayModeIndex = [controller indexOfCurrentDisplayMode];
|
|
if (displayModeIndex == NSNotFound)
|
|
{
|
|
NSLog(@"***** couldn't find current display mode switching to basic 640x480");
|
|
displayModeIndex = 0;
|
|
}
|
|
|
|
// oolite-linux:
|
|
// Check that there are display modes listed before trying to
|
|
// get them or an exception occurs.
|
|
NSDictionary *mode = nil;
|
|
if ([(NSArray *)[controller displayModes] count])
|
|
{
|
|
mode=[(NSArray *)[controller displayModes] objectAtIndex:displayModeIndex];
|
|
}
|
|
int modeWidth = [[mode objectForKey: (NSString *)kCGDisplayWidth] intValue];
|
|
int modeHeight = [[mode objectForKey: (NSString *)kCGDisplayHeight] intValue];
|
|
int modeRefresh = [[mode objectForKey: (NSString *)kCGDisplayRefreshRate] intValue];
|
|
|
|
NSString *displayModeString = [NSString stringWithFormat:@" Fullscreen: %d x %d at %d Hz ", modeWidth, modeHeight, modeRefresh];
|
|
#endif
|
|
|
|
// GUI stuff
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
int quicksave_row = GUI_ROW_OPTIONS_QUICKSAVE;
|
|
int save_row = GUI_ROW_OPTIONS_SAVE;
|
|
int load_row = GUI_ROW_OPTIONS_LOAD;
|
|
int begin_new_row = GUI_ROW_OPTIONS_BEGIN_NEW;
|
|
int options_row = GUI_ROW_OPTIONS_OPTIONS;
|
|
#ifdef GNUSTEP
|
|
// GNUstep needs a quit option at present (no Cmd-Q) but
|
|
// doesn't need speech.
|
|
int quit_row = GUI_ROW_OPTIONS_QUIT;
|
|
#else
|
|
int display_row = GUI_ROW_OPTIONS_DISPLAY;
|
|
int speech_row = GUI_ROW_OPTIONS_SPEECH;
|
|
#endif
|
|
int ootunes_row = GUI_ROW_OPTIONS_OOTUNES;
|
|
int detail_row = GUI_ROW_OPTIONS_DETAIL;
|
|
int strict_row = GUI_ROW_OPTIONS_STRICT;
|
|
|
|
#ifdef GNUSTEP
|
|
int first_sel_row = (canLoadOrSave)? save_row : ootunes_row;
|
|
#else
|
|
int first_sel_row = (canLoadOrSave)? save_row : display_row;
|
|
#endif
|
|
if (canQuickSave)
|
|
first_sel_row = quicksave_row;
|
|
|
|
[gui clear];
|
|
[gui setTitle:[NSString stringWithFormat:@"Commander %@", player_name]];
|
|
//
|
|
if (canQuickSave)
|
|
[gui setText:@" Quick-Save " forRow:quicksave_row align:GUI_ALIGN_CENTER];
|
|
[gui setText:@" Save Commander " forRow:save_row align:GUI_ALIGN_CENTER];
|
|
[gui setText:@" Load Commander " forRow:load_row align:GUI_ALIGN_CENTER];
|
|
[gui setText:@" Begin New Game " forRow:begin_new_row align:GUI_ALIGN_CENTER];
|
|
[gui setText:@"Game Options:" forRow:options_row align:GUI_ALIGN_CENTER];
|
|
if (!canLoadOrSave)
|
|
{
|
|
[gui setColor:[NSColor grayColor] forRow:save_row];
|
|
[gui setColor:[NSColor grayColor] forRow:load_row];
|
|
}
|
|
[gui setColor:[NSColor grayColor] forRow:options_row];
|
|
#ifdef GNUSTEP
|
|
// TODO: This menu section is preliminary.
|
|
if (ootunes_on)
|
|
[gui setText:@" xine integration: ON " forRow:ootunes_row align:GUI_ALIGN_CENTER];
|
|
else
|
|
[gui setText:@" xine integration: OFF " forRow:ootunes_row align:GUI_ALIGN_CENTER];
|
|
// full screen mode is probably not possible in GNUstep.
|
|
// [gui setText:displayModeString
|
|
// forRow:display_row align:GUI_ALIGN_CENTER];
|
|
|
|
// quit menu option
|
|
[gui setText:@" Exit game " forRow:quit_row align:GUI_ALIGN_CENTER];
|
|
#else
|
|
// Macintosh only
|
|
if (speech_on)
|
|
[gui setText:@" Spoken messages: ON " forRow:speech_row align:GUI_ALIGN_CENTER];
|
|
else
|
|
[gui setText:@" Spoken messages: OFF " forRow:speech_row align:GUI_ALIGN_CENTER];
|
|
if (ootunes_on)
|
|
[gui setText:@" iTunes integration: ON " forRow:ootunes_row align:GUI_ALIGN_CENTER];
|
|
else
|
|
[gui setText:@" iTunes integration: OFF " forRow:ootunes_row align:GUI_ALIGN_CENTER];
|
|
#endif
|
|
if ([universe reducedDetail])
|
|
[gui setText:@" Reduced detail: ON " forRow:detail_row align:GUI_ALIGN_CENTER];
|
|
else
|
|
[gui setText:@" Reduced detail: OFF " forRow:detail_row align:GUI_ALIGN_CENTER];
|
|
if ([universe strict])
|
|
[gui setText:@" Reset to unrestricted play. " forRow:strict_row align:GUI_ALIGN_CENTER];
|
|
else
|
|
[gui setText:@" Reset to strict gameplay. " forRow:strict_row align:GUI_ALIGN_CENTER];
|
|
#ifdef GNUSTEP
|
|
[gui setSelectableRange:NSMakeRange(first_sel_row, 1 + quit_row - first_sel_row)];
|
|
#else
|
|
[gui setSelectableRange:NSMakeRange(first_sel_row ,1 + strict_row - first_sel_row)];
|
|
#endif
|
|
[gui setSelectedRow: first_sel_row];
|
|
//
|
|
|
|
[gui setShowTextCursor:NO];
|
|
|
|
// [gui generateDisplay];
|
|
[universe guiUpdated];
|
|
}
|
|
/* ends */
|
|
|
|
//NSLog(@"gui_screen = GUI_SCREEN_OPTIONS");
|
|
|
|
[self setShowDemoShips:NO];
|
|
gui_screen = GUI_SCREEN_OPTIONS;
|
|
}
|
|
|
|
static int last_outfitting_index;
|
|
|
|
- (void) setGuiToEquipShipScreen:(int) skip :(int) itemForSelectFacing
|
|
{
|
|
missiles = [self calc_missiles];
|
|
|
|
// NSLog(@"DEBUG EquipShipScreen missiles = %d", missiles);
|
|
|
|
// if skip < 0 then use the last recorded index
|
|
if (skip < 0)
|
|
{
|
|
if (last_outfitting_index >= 0)
|
|
skip = last_outfitting_index;
|
|
else
|
|
skip = 0;
|
|
}
|
|
last_outfitting_index = skip;
|
|
|
|
NSArray* equipdata = [universe equipmentdata];
|
|
|
|
int cargo_space = max_cargo - current_cargo;
|
|
|
|
double price_factor = 1.0;
|
|
int techlevel = [(NSNumber *)[[universe generateSystemData:system_seed] objectForKey:KEY_TECHLEVEL] intValue];
|
|
|
|
if (docked_station)
|
|
{
|
|
price_factor = [docked_station equipment_price_factor];
|
|
if ([docked_station equivalent_tech_level] != NSNotFound)
|
|
techlevel = [docked_station equivalent_tech_level];
|
|
}
|
|
|
|
// build an array of all equipment - and take away that which has been bought (or is not permitted)
|
|
NSMutableArray* equipment_allowed = [NSMutableArray arrayWithCapacity:120];
|
|
//
|
|
// find options that agree with this ship
|
|
BOOL option_okay[[equipdata count]];
|
|
NSMutableArray* options = [NSMutableArray arrayWithArray:(NSArray*)[(NSDictionary*)[[universe shipyard] objectForKey:ship_desc] objectForKey:KEY_OPTIONAL_EQUIPMENT]];
|
|
[options addObject:@"EQ_FUEL"];
|
|
[options addObject:@"EQ_PASSENGER_BERTH"];
|
|
[options addObject:@"EQ_PASSENGER_BERTH_REMOVAL"];
|
|
[options addObject:@"EQ_ADVANCED_COMPASS"];
|
|
int i,j;
|
|
for (i = 0; i < [equipdata count]; i++)
|
|
{
|
|
NSString* eq_key = (NSString*)[(NSArray*)[equipdata objectAtIndex:i] objectAtIndex:EQUIPMENT_KEY_INDEX];
|
|
int min_techlevel = [(NSNumber *)[(NSArray *)[equipdata objectAtIndex:i] objectAtIndex:EQUIPMENT_TECH_LEVEL_INDEX] intValue];
|
|
|
|
// reduce the minimum techlevel occasionally as a bonus..
|
|
//
|
|
if ((![universe strict])&&(techlevel < min_techlevel)&&(techlevel > min_techlevel - 3))
|
|
{
|
|
int day = i * 13 + floor([universe getTime] / 86400.0);
|
|
unsigned char day_rnd = (day & 0xff) ^ system_seed.a;
|
|
int original_min_techlevel = min_techlevel;
|
|
//
|
|
while ((min_techlevel > 0)&&(min_techlevel > original_min_techlevel - 3)&&!(day_rnd & 7)) // bargain tech days every 1/8 days
|
|
{
|
|
day_rnd = day_rnd >> 2;
|
|
min_techlevel--;
|
|
}
|
|
if (min_techlevel < original_min_techlevel)
|
|
NSLog(@"DEBUG -- Bargain tech day for %@ (TL %d reduced from %d)", eq_key, min_techlevel, original_min_techlevel);
|
|
}
|
|
|
|
option_okay[i] = [eq_key hasPrefix:@"EQ_WEAPON"];
|
|
for (j = 0; j < [options count]; j++)
|
|
{
|
|
if ([eq_key isEqual:[options objectAtIndex:j]])
|
|
{
|
|
option_okay[i] = YES;
|
|
[options removeObjectAtIndex:j];
|
|
j = [options count];
|
|
}
|
|
}
|
|
if (([eq_key isEqual:@"EQ_FUEL"])&&(fuel >= 70))
|
|
option_okay[i] = NO;
|
|
if (([eq_key hasSuffix:@"MISSILE"]||[eq_key hasSuffix:@"MINE"]))
|
|
option_okay[i] = (missiles < max_missiles);
|
|
if (([eq_key isEqual:@"EQ_PASSENGER_BERTH"])&&(cargo_space < 5))
|
|
option_okay[i] = NO;
|
|
if (([eq_key isEqual:@"EQ_PASSENGER_BERTH_REMOVAL"])&&(max_passengers - [passengers count] < 1))
|
|
option_okay[i] = NO;
|
|
if ([self has_extra_equipment:eq_key])
|
|
option_okay[i] = NO;
|
|
if ([eq_key isEqual:@"EQ_ENERGY_UNIT"]&&[self has_extra_equipment:@"EQ_NAVAL_ENERGY_UNIT"])
|
|
option_okay[i] = NO;
|
|
if (techlevel < min_techlevel)
|
|
option_okay[i] = NO;
|
|
|
|
if (option_okay[i])
|
|
[equipment_allowed addObject: [NSNumber numberWithInt:i]];
|
|
|
|
if (i == itemForSelectFacing)
|
|
{
|
|
skip = [equipment_allowed count] - 1; // skip to this upgrade
|
|
int available_facings = [(NSNumber*)[(NSDictionary*)[[universe shipyard] objectForKey:ship_desc] objectForKey:KEY_WEAPON_FACINGS] intValue];
|
|
if (available_facings & WEAPON_FACING_FORWARD)
|
|
[equipment_allowed addObject: [NSNumber numberWithInt:i]];
|
|
if (available_facings & WEAPON_FACING_AFT)
|
|
[equipment_allowed addObject: [NSNumber numberWithInt:i]];
|
|
if (available_facings & WEAPON_FACING_PORT)
|
|
[equipment_allowed addObject: [NSNumber numberWithInt:i]];
|
|
if (available_facings & WEAPON_FACING_STARBOARD)
|
|
[equipment_allowed addObject: [NSNumber numberWithInt:i]];
|
|
}
|
|
}
|
|
|
|
// GUI stuff
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
|
|
int start_row = GUI_ROW_EQUIPMENT_START;
|
|
int row = start_row;
|
|
int i;
|
|
int tab_stops[GUI_MAX_COLUMNS];
|
|
int facing_count = 0;
|
|
|
|
[gui clear];
|
|
[gui setTitle:@"Ship Outfitting"];
|
|
//
|
|
[gui setText:[NSString stringWithFormat:@"Cash:\t%.1f Cr.", 0.1*credits] forRow: GUI_ROW_EQUIPMENT_CASH];
|
|
//
|
|
tab_stops[0] = 0;
|
|
tab_stops[1] = 320;
|
|
//
|
|
[gui setTabStops:tab_stops];
|
|
//
|
|
int n_rows = GUI_MAX_ROWS_EQUIPMENT;
|
|
//
|
|
if ([equipment_allowed count] > 0)
|
|
{
|
|
// double check for sound values of skip
|
|
if ((skip < 0)||(skip >= [equipment_allowed count]))
|
|
skip = 0;
|
|
//
|
|
if (skip > 0) // lose the first row to Back <--
|
|
{
|
|
int previous = skip - n_rows;
|
|
if (previous < 0) previous = 0;
|
|
if (itemForSelectFacing >= 0)
|
|
previous = -1; // ie. last index!
|
|
[gui setColor:[NSColor greenColor] forRow:row];
|
|
[gui setArray:[NSArray arrayWithObjects:@" Back ", @" <-- ", nil] forRow:row];
|
|
[gui setKey:[NSString stringWithFormat:@"More:%d", previous] forRow:row];
|
|
row++;
|
|
}
|
|
for (i = skip; (i < [equipment_allowed count])&&(row - start_row < n_rows - 1); i++)
|
|
{
|
|
int item = [(NSNumber *)[equipment_allowed objectAtIndex:i] intValue];
|
|
|
|
int price_per_unit = [(NSNumber *)[(NSArray *)[equipdata objectAtIndex:item] objectAtIndex:EQUIPMENT_PRICE_INDEX] intValue];
|
|
NSString* desc = [NSString stringWithFormat:@" %@ ",[(NSArray *)[equipdata objectAtIndex:item] objectAtIndex:EQUIPMENT_SHORT_DESC_INDEX]];
|
|
NSString* eq_type = (NSString *)[(NSArray *)[equipdata objectAtIndex:item] objectAtIndex:EQUIPMENT_KEY_INDEX];
|
|
double price = ([eq_type isEqual:@"EQ_FUEL"]) ? ((70 - fuel) * price_per_unit) : (price_per_unit) ;
|
|
|
|
price *= price_factor; // increased prices at some stations
|
|
|
|
NSString* priceString = [NSString stringWithFormat:@" %.1f ",0.1*price];
|
|
|
|
if (item == itemForSelectFacing)
|
|
{
|
|
if (facing_count == 0)
|
|
priceString = @"";
|
|
if (facing_count == 1)
|
|
desc = FORWARD_FACING_STRING;
|
|
if (facing_count == 1)
|
|
desc = FORWARD_FACING_STRING;
|
|
if (facing_count == 2)
|
|
desc = AFT_FACING_STRING;
|
|
if (facing_count == 3)
|
|
desc = PORT_FACING_STRING;
|
|
if (facing_count == 4)
|
|
desc = STARBOARD_FACING_STRING;
|
|
facing_count++;
|
|
[gui setColor:[NSColor greenColor] forRow:row];
|
|
}
|
|
[gui setKey:[NSString stringWithFormat:@"%d",item] forRow:row]; // save the index of the item as the key for the row
|
|
[gui setArray:[NSArray arrayWithObjects:desc, priceString, nil] forRow:row];
|
|
row++;
|
|
}
|
|
if (i < [equipment_allowed count])
|
|
{
|
|
[gui setColor:[NSColor greenColor] forRow:row];
|
|
[gui setArray:[NSArray arrayWithObjects:@" More ", @" --> ", nil] forRow:row];
|
|
[gui setKey:[NSString stringWithFormat:@"More:%d", i] forRow:row];
|
|
row++;
|
|
}
|
|
//
|
|
[gui setSelectableRange:NSMakeRange(start_row,row - start_row)];
|
|
|
|
if ([gui selectedRow] < start_row)
|
|
[gui setSelectedRow:start_row];
|
|
|
|
if (itemForSelectFacing >= 0)
|
|
[gui setSelectedRow:start_row + ((skip > 0)? 1: 0)];
|
|
|
|
[self showInformationForSelectedUpgrade];
|
|
//
|
|
}
|
|
else
|
|
{
|
|
[gui setText:@"No equipment available for purchase." forRow:GUI_ROW_NO_SHIPS align:GUI_ALIGN_CENTER];
|
|
[gui setColor:[NSColor greenColor] forRow:GUI_ROW_NO_SHIPS];
|
|
//
|
|
[gui setSelectableRange:NSMakeRange(0,0)];
|
|
[gui setNoSelectedRow];
|
|
[self showInformationForSelectedUpgrade];
|
|
}
|
|
|
|
[gui setShowTextCursor:NO];
|
|
|
|
[universe guiUpdated];
|
|
}
|
|
/* ends */
|
|
|
|
chosen_weapon_facing = WEAPON_FACING_NONE;
|
|
[self setShowDemoShips:NO];
|
|
gui_screen = GUI_SCREEN_EQUIP_SHIP;
|
|
}
|
|
|
|
- (void) showInformationForSelectedUpgrade
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
NSString* key = [gui selectedRowKey];
|
|
int i;
|
|
for (i = GUI_ROW_EQUIPMENT_DETAIL; i < GUI_MAX_ROWS; i++)
|
|
{
|
|
[gui setText:@"" forRow:i];
|
|
[gui setColor:[NSColor greenColor] forRow:i];
|
|
}
|
|
if (key)
|
|
{
|
|
if (![key hasPrefix:@"More:"])
|
|
{
|
|
int item = [key intValue];
|
|
NSString* desc = (NSString *)[(NSArray *)[[universe equipmentdata] objectAtIndex:item] objectAtIndex:EQUIPMENT_LONG_DESC_INDEX];
|
|
[gui addLongText:desc startingAtRow:GUI_ROW_EQUIPMENT_DETAIL align:GUI_ALIGN_LEFT];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) setGuiToIntro1Screen
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
|
|
// GUI stuff
|
|
{
|
|
int ms_line = 2;
|
|
|
|
[gui clear];
|
|
[gui setTitle:@"Oolite"];
|
|
//
|
|
[gui setText:@"by Giles Williams (C) 2003-2005" forRow:17 align:GUI_ALIGN_CENTER];
|
|
[gui setColor:[NSColor whiteColor] forRow:17];
|
|
//
|
|
[gui setText:@"Oolite Theme Music by No Sleep (C) 2004" forRow:19 align:GUI_ALIGN_CENTER];
|
|
[gui setColor:[NSColor grayColor] forRow:19];
|
|
//
|
|
[gui setText:@"Load Previous Commander (Y/N)?" forRow:21 align:GUI_ALIGN_CENTER];
|
|
[gui setColor:[NSColor yellowColor] forRow:21];
|
|
|
|
//
|
|
// check for error messages from Resource Manager
|
|
//
|
|
if (([ResourceManager pathsUsingAddOns:YES])&&([ResourceManager errors]))
|
|
{
|
|
int ms_start = ms_line;
|
|
int i = ms_line = [gui addLongText:[ResourceManager errors] startingAtRow:ms_start align:GUI_ALIGN_LEFT];
|
|
for (i-- ; i >= ms_start ; i--) [gui setColor:[NSColor redColor] forRow:i];
|
|
ms_line++;
|
|
}
|
|
|
|
//NSLog(@"<<<<< DEBUG1");
|
|
|
|
//
|
|
// check for messages from the command line
|
|
//
|
|
NSArray* arguments = [[NSProcessInfo processInfo] arguments];
|
|
//NSLog(@"DEBUG arguments:\n%@",[arguments description]);
|
|
int i;
|
|
for (i = 0; i < [arguments count]; i++)
|
|
{
|
|
if (([[arguments objectAtIndex:i] isEqual:@"-message"])&&(i < [arguments count] - 1))
|
|
{
|
|
int ms_start = ms_line;
|
|
NSString* message = (NSString*)[arguments objectAtIndex: i + 1];
|
|
int i = ms_line = [gui addLongText:message startingAtRow:ms_start align:GUI_ALIGN_CENTER];
|
|
for (i-- ; i >= ms_start; i--) [gui setColor:[NSColor magentaColor] forRow:i];
|
|
}
|
|
if ([[arguments objectAtIndex:i] isEqual:@"-showversion"])
|
|
{
|
|
int ms_start = ms_line;
|
|
NSString *version = [NSString stringWithFormat:@"Version %@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]];
|
|
int i = ms_line = [gui addLongText:version startingAtRow:ms_start align:GUI_ALIGN_CENTER];
|
|
for (i-- ; i >= ms_start; i--) [gui setColor:[NSColor magentaColor] forRow:i];
|
|
}
|
|
}
|
|
|
|
// [gui generateDisplay];
|
|
|
|
[gui setShowTextCursor:NO];
|
|
|
|
[universe guiUpdated];
|
|
}
|
|
/* ends */
|
|
|
|
//NSLog(@"<<<<< DEBUG2");
|
|
|
|
[universe set_up_intro1];
|
|
|
|
if (gui)
|
|
gui_screen = GUI_SCREEN_INTRO1;
|
|
|
|
if (themeMusic)
|
|
{
|
|
#ifndef GNUSTEP
|
|
GoToBeginningOfMovie ([themeMusic QTMovie]);
|
|
StartMovie ([themeMusic QTMovie]);
|
|
#else
|
|
[themeMusic stop];
|
|
[themeMusic goToBeginning];
|
|
[themeMusic play];
|
|
#endif
|
|
}
|
|
}
|
|
|
|
- (void) setGuiToIntro2Screen
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
|
|
// GUI stuff
|
|
{
|
|
[gui clear];
|
|
[gui setTitle:@"Oolite"];
|
|
//
|
|
[gui setText:@"Press Space Commander" forRow:21 align:GUI_ALIGN_CENTER];
|
|
[gui setColor:[NSColor yellowColor] forRow:21];
|
|
//
|
|
// [gui generateDisplay];
|
|
|
|
[gui setShowTextCursor:NO];
|
|
|
|
[universe guiUpdated];
|
|
}
|
|
/* ends */
|
|
|
|
[universe set_up_intro2];
|
|
|
|
if (gui)
|
|
gui_screen = GUI_SCREEN_INTRO2;
|
|
}
|
|
|
|
- (void) buySelectedItem
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
NSString* key = [gui selectedRowKey];
|
|
|
|
if ([key hasPrefix:@"More:"])
|
|
{
|
|
int from_item = [(NSString*)[[key componentsSeparatedByString:@":"] objectAtIndex:1] intValue];
|
|
|
|
[self setGuiToEquipShipScreen:from_item:-1];
|
|
if ([gui selectedRow] < 0)
|
|
[gui setSelectedRow:GUI_ROW_EQUIPMENT_START];
|
|
if (from_item == 0)
|
|
[gui setSelectedRow:GUI_ROW_EQUIPMENT_START + GUI_MAX_ROWS_EQUIPMENT - 1];
|
|
return;
|
|
}
|
|
//
|
|
int item = [key intValue];
|
|
NSString *item_text = [gui selectedRowText];
|
|
if ([item_text isEqual:FORWARD_FACING_STRING])
|
|
chosen_weapon_facing = WEAPON_FACING_FORWARD;
|
|
if ([item_text isEqual:AFT_FACING_STRING])
|
|
chosen_weapon_facing = WEAPON_FACING_AFT;
|
|
if ([item_text isEqual:PORT_FACING_STRING])
|
|
chosen_weapon_facing = WEAPON_FACING_PORT;
|
|
if ([item_text isEqual:STARBOARD_FACING_STRING])
|
|
chosen_weapon_facing = WEAPON_FACING_STARBOARD;
|
|
//NSLog(@"Try Buying Item %d",item);
|
|
int old_credits = credits;
|
|
if ([self tryBuyingItem:item])
|
|
{
|
|
if (credits == old_credits)
|
|
{
|
|
[[universe gui] click];
|
|
}
|
|
else
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if ([buySound isPlaying])
|
|
[buySound stop];
|
|
[buySound play];
|
|
#endif
|
|
//
|
|
// wind the clock forward by 10 minutes plus 10 minutes for every 60 credits spent
|
|
//
|
|
double time_adjust = (old_credits > credits)? (old_credits - credits): 0.0;
|
|
ship_clock_adjust += time_adjust + 600.0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef HAVE_SOUND
|
|
if ([boopSound isPlaying])
|
|
[boopSound stop];
|
|
[boopSound play];
|
|
#endif
|
|
}
|
|
}
|
|
|
|
- (BOOL) tryBuyingItem:(int) index
|
|
{
|
|
// note this doesn't check the availability by tech-level
|
|
//
|
|
NSArray* equipdata = [universe equipmentdata];
|
|
int price_per_unit = [(NSNumber *)[(NSArray *)[equipdata objectAtIndex:index] objectAtIndex:EQUIPMENT_PRICE_INDEX] intValue];
|
|
NSString* eq_type = (NSString *)[(NSArray *)[equipdata objectAtIndex:index] objectAtIndex:EQUIPMENT_KEY_INDEX];
|
|
double price = ([eq_type isEqual:@"EQ_FUEL"]) ? ((70 - fuel) * price_per_unit) : (price_per_unit) ;
|
|
double price_factor = 1.0;
|
|
int cargo_space = max_cargo - current_cargo;
|
|
|
|
if (docked_station)
|
|
{
|
|
price_factor = [docked_station equipment_price_factor];
|
|
}
|
|
|
|
price *= price_factor; // increased prices at some stations
|
|
|
|
if (price > credits)
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
if (([eq_type hasPrefix:@"EQ_WEAPON"])&&(chosen_weapon_facing == WEAPON_FACING_NONE))
|
|
{
|
|
[self setGuiToEquipShipScreen:-1:index]; // reset
|
|
return YES;
|
|
}
|
|
|
|
if (([eq_type hasPrefix:@"EQ_WEAPON"])&&(chosen_weapon_facing != WEAPON_FACING_NONE))
|
|
{
|
|
int chosen_weapon = WEAPON_NONE;
|
|
int current_weapon = WEAPON_NONE;
|
|
|
|
if ([eq_type isEqual:@"EQ_WEAPON_TWIN_PLASMA_CANNON"])
|
|
chosen_weapon = WEAPON_PLASMA_CANNON;
|
|
if ([eq_type isEqual:@"EQ_WEAPON_PULSE_LASER"])
|
|
chosen_weapon = WEAPON_PULSE_LASER;
|
|
if ([eq_type isEqual:@"EQ_WEAPON_BEAM_LASER"])
|
|
chosen_weapon = WEAPON_BEAM_LASER;
|
|
if ([eq_type isEqual:@"EQ_WEAPON_MINING_LASER"])
|
|
chosen_weapon = WEAPON_MINING_LASER;
|
|
if ([eq_type isEqual:@"EQ_WEAPON_MILITARY_LASER"])
|
|
chosen_weapon = WEAPON_MILITARY_LASER;
|
|
if ([eq_type isEqual:@"EQ_WEAPON_THARGOID_LASER"])
|
|
chosen_weapon = WEAPON_THARGOID_LASER;
|
|
|
|
switch (chosen_weapon_facing)
|
|
{
|
|
case WEAPON_FACING_FORWARD :
|
|
current_weapon = forward_weapon;
|
|
forward_weapon = chosen_weapon;
|
|
break;
|
|
case WEAPON_FACING_AFT :
|
|
current_weapon = aft_weapon;
|
|
aft_weapon = chosen_weapon;
|
|
break;
|
|
case WEAPON_FACING_PORT :
|
|
current_weapon = port_weapon;
|
|
port_weapon = chosen_weapon;
|
|
break;
|
|
case WEAPON_FACING_STARBOARD :
|
|
current_weapon = starboard_weapon;
|
|
starboard_weapon = chosen_weapon;
|
|
break;
|
|
}
|
|
|
|
credits -= price;
|
|
|
|
// refund here for current_weapon;
|
|
switch (current_weapon)
|
|
{
|
|
case WEAPON_PLASMA_CANNON :
|
|
credits += [universe getPriceForWeaponSystemWithKey:@"EQ_WEAPON_TWIN_PLASMA_CANNON"];
|
|
break;
|
|
case WEAPON_PULSE_LASER :
|
|
credits += [universe getPriceForWeaponSystemWithKey:@"EQ_WEAPON_PULSE_LASER"];
|
|
break;
|
|
case WEAPON_BEAM_LASER :
|
|
credits += [universe getPriceForWeaponSystemWithKey:@"EQ_WEAPON_BEAM_LASER"];
|
|
break;
|
|
case WEAPON_MINING_LASER :
|
|
credits += [universe getPriceForWeaponSystemWithKey:@"EQ_WEAPON_MINING_LASER"];
|
|
break;
|
|
case WEAPON_MILITARY_LASER :
|
|
credits += [universe getPriceForWeaponSystemWithKey:@"EQ_WEAPON_MILITARY_LASER"];
|
|
break;
|
|
case WEAPON_THARGOID_LASER :
|
|
credits += [universe getPriceForWeaponSystemWithKey:@"EQ_WEAPON_THARGOID_LASER"];
|
|
break;
|
|
case WEAPON_NONE :
|
|
break;
|
|
}
|
|
|
|
[self setGuiToEquipShipScreen:-1:-1];
|
|
return YES;
|
|
}
|
|
|
|
if (([eq_type hasSuffix:@"MISSILE"]||[eq_type hasSuffix:@"MINE"])&&(missiles >= max_missiles))
|
|
return NO;
|
|
|
|
if (([eq_type isEqual:@"EQ_PASSENGER_BERTH"])&&(cargo_space < 5))
|
|
return NO;
|
|
|
|
if ([eq_type isEqual:@"EQ_FUEL"])
|
|
{
|
|
fuel = 70;
|
|
credits -= price;
|
|
[self setGuiToEquipShipScreen:-1:-1];
|
|
return YES;
|
|
}
|
|
|
|
if ([eq_type hasSuffix:@"MISSILE"]||[eq_type hasSuffix:@"MINE"])
|
|
{
|
|
ShipEntity* weapon = [[universe getShipWithRole:eq_type] autorelease];
|
|
BOOL mounted_okay = [self mountMissile:weapon];
|
|
if (mounted_okay)
|
|
{
|
|
credits -= price;
|
|
[self safe_all_missiles];
|
|
[self sort_missiles];
|
|
[self select_next_missile];
|
|
}
|
|
[self setGuiToEquipShipScreen:-1:-1];
|
|
return mounted_okay;
|
|
}
|
|
|
|
if ([eq_type isEqual:@"EQ_PASSENGER_BERTH"])
|
|
{
|
|
max_passengers++;
|
|
max_cargo -= 5;
|
|
credits -= price;
|
|
[self setGuiToEquipShipScreen:-1:-1];
|
|
return YES;
|
|
}
|
|
|
|
if ([eq_type isEqual:@"EQ_PASSENGER_BERTH_REMOVAL"])
|
|
{
|
|
max_passengers--;
|
|
max_cargo += 5;
|
|
credits -= price;
|
|
[self setGuiToEquipShipScreen:-1:-1];
|
|
return YES;
|
|
}
|
|
|
|
int i;
|
|
for (i =0; i < [equipdata count]; i++)
|
|
{
|
|
NSString *w_key = (NSString *)[(NSArray *)[equipdata objectAtIndex:i] objectAtIndex:EQUIPMENT_KEY_INDEX];
|
|
if (([eq_type isEqual:w_key])&&(![self has_extra_equipment:eq_type]))
|
|
{
|
|
//NSLog(@"adding %@",eq_type);
|
|
credits -= price;
|
|
[self add_extra_equipment:eq_type];
|
|
[self setGuiToEquipShipScreen:-1:-1];
|
|
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (void) setGuiToMarketScreen
|
|
{
|
|
NSArray* localMarket;
|
|
|
|
if (status == STATUS_DOCKED)
|
|
{
|
|
if (docked_station == nil)
|
|
docked_station = [universe station];
|
|
if ([docked_station localMarket])
|
|
localMarket = [docked_station localMarket];
|
|
else
|
|
localMarket = [docked_station initialiseLocalMarketWithSeed:system_seed andRandomFactor:market_rnd];
|
|
}
|
|
else
|
|
{
|
|
if ([[universe station] localMarket])
|
|
localMarket = [[universe station] localMarket];
|
|
else
|
|
localMarket = [[universe station] initialiseLocalMarketWithSeed:system_seed andRandomFactor:market_rnd];
|
|
}
|
|
|
|
// NSLog(@"DEBUG local market = %@ [universe station] = %@", [localMarket description], [universe station]);
|
|
|
|
// GUI stuff
|
|
{
|
|
GuiDisplayGen* gui = [universe gui];
|
|
|
|
int start_row = GUI_ROW_MARKET_START;
|
|
int row = start_row;
|
|
int i;
|
|
int tab_stops[GUI_MAX_COLUMNS];
|
|
int n_commodities = [localMarket count];
|
|
int in_hold[n_commodities];
|
|
|
|
if (status == STATUS_DOCKED)
|
|
{
|
|
for (i = 0; i < n_commodities; i++)
|
|
in_hold[i] = [(NSNumber *)[(NSArray *)[shipCommodityData objectAtIndex:i] objectAtIndex:MARKET_QUANTITY] intValue];
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < n_commodities; i++)
|
|
in_hold[i] = 0;
|
|
for (i = 0; i < [cargo count]; i++)
|
|
{
|
|
ShipEntity *container = (ShipEntity *)[cargo objectAtIndex:i];
|
|
in_hold[[container getCommodityType]] += [container getCommodityAmount];
|
|
}
|
|
}
|
|
|
|
[gui clear];
|
|
[gui setTitle:[NSString stringWithFormat:@"%@ Commodity Market",[universe getSystemName:system_seed]]];
|
|
//
|
|
tab_stops[0] = 0;
|
|
tab_stops[1] = 192;
|
|
tab_stops[2] = 288;
|
|
tab_stops[3] = 384;
|
|
//
|
|
[gui setTabStops:tab_stops];
|
|
//
|
|
[gui setColor:[NSColor greenColor] forRow:GUI_ROW_MARKET_KEY];
|
|
[gui setArray:[NSArray arrayWithObjects: @"Commodity:", @"Price:", @"For sale:", @"In hold:", nil] forRow:GUI_ROW_MARKET_KEY];
|
|
//
|
|
current_cargo = 0; // for calculating remaining hold space
|
|
//
|
|
for (i = 0; i < n_commodities; i++)
|
|
{
|
|
NSString* desc = [NSString stringWithFormat:@" %@ ",(NSString *)[(NSArray *)[localMarket objectAtIndex:i] objectAtIndex:MARKET_NAME]];
|
|
int available_units = [(NSNumber *)[(NSArray *)[localMarket objectAtIndex:i] objectAtIndex:MARKET_QUANTITY] intValue];
|
|
int units_in_hold = in_hold[i];
|
|
int price_per_unit = [(NSNumber *)[(NSArray *)[localMarket objectAtIndex:i] objectAtIndex:MARKET_PRICE] intValue];
|
|
int unit = [(NSNumber *)[(NSArray *)[localMarket objectAtIndex:i] objectAtIndex:MARKET_UNITS] intValue];
|
|
NSString* available = (available_units > 0) ? [NSString stringWithFormat:@"%d",available_units] : @"-";
|
|
NSString* price = [NSString stringWithFormat:@" %.1f ",0.1*price_per_unit];
|
|
NSString* owned = (units_in_hold > 0) ? [NSString stringWithFormat:@"%d",units_in_hold] : @"-";
|
|
NSString* units = @"t";
|
|
if (unit == UNITS_KILOGRAMS) units = @"kg";
|
|
if (unit == UNITS_GRAMS) units = @"g";
|
|
NSString* units_available = [NSString stringWithFormat:@" %@ %@ ",available,units];
|
|
NSString* units_owned = [NSString stringWithFormat:@" %@ %@ ",owned,units];
|
|
|
|
if (unit == UNITS_TONS)
|
|
current_cargo += units_in_hold;
|
|
|
|
[gui setKey:[NSString stringWithFormat:@"%d",i] forRow:row];
|
|
[gui setArray:[NSArray arrayWithObjects: desc, price, units_available, units_owned, nil] forRow:row++];
|
|
}
|
|
//
|
|
if ([cargo count] > 0)
|
|
current_cargo = ([cargo count] <= max_cargo) ? [cargo count] : max_cargo; // actually count the containers and things (may be > max_cargo)
|
|
//
|
|
[gui setText:[NSString stringWithFormat:@"Cash:\t%.1f Cr.\t\tLoad %d of %d t.", 0.1*credits, current_cargo, max_cargo] forRow: GUI_ROW_MARKET_CASH];
|
|
//
|
|
if (status == STATUS_DOCKED) // can only buy or sell in dock
|
|
{
|
|
[gui setSelectableRange:NSMakeRange(start_row,row - start_row)];
|
|
if (([gui selectedRow] < start_row)||([gui selectedRow] >=row))
|
|
[gui setSelectedRow:start_row];
|
|
}
|
|
else
|
|
{
|
|
[gui setNoSelectedRow];
|
|
}
|
|
//
|
|
|
|
[gui setShowTextCursor:NO];
|
|
|
|
[universe guiUpdated];
|
|
}
|
|
|
|
[self setShowDemoShips:NO];
|
|
gui_screen = GUI_SCREEN_MARKET;
|
|
}
|
|
|
|
- (int) gui_screen
|
|
{
|
|
return gui_screen;
|
|
}
|
|
|
|
- (BOOL) marketFlooded:(int) index
|
|
{
|
|
NSMutableArray* localMarket;
|
|
if (docked_station == nil)
|
|
docked_station = [universe station];
|
|
if ([docked_station localMarket])
|
|
localMarket = [docked_station localMarket];
|
|
else
|
|
localMarket = [docked_station initialiseLocalMarketWithSeed:system_seed andRandomFactor:market_rnd];
|
|
NSArray *commodityArray = (NSArray *)[localMarket objectAtIndex:index];
|
|
int available_units = [(NSNumber *)[commodityArray objectAtIndex:MARKET_QUANTITY] intValue];
|
|
return (available_units >= 127);
|
|
}
|
|
|
|
- (BOOL) tryBuyingCommodity:(int) index
|
|
{
|
|
NSMutableArray* localMarket;
|
|
if (status == STATUS_DOCKED)
|
|
{
|
|
if (docked_station == nil)
|
|
docked_station = [universe station];
|
|
if ([docked_station localMarket])
|
|
localMarket = [docked_station localMarket];
|
|
else
|
|
localMarket = [docked_station initialiseLocalMarketWithSeed:system_seed andRandomFactor:market_rnd];
|
|
}
|
|
else
|
|
{
|
|
return NO; // can't buy if not docked
|
|
}
|
|
|
|
NSArray *commodityArray = (NSArray *)[localMarket objectAtIndex:index];
|
|
int available_units = [(NSNumber *)[commodityArray objectAtIndex:MARKET_QUANTITY] intValue];
|
|
int price_per_unit = [(NSNumber *)[commodityArray objectAtIndex:MARKET_PRICE] intValue];
|
|
int unit = [(NSNumber *)[commodityArray objectAtIndex:MARKET_UNITS] intValue];
|
|
|
|
if ((specialCargo != nil)&&(unit == 0))
|
|
return NO; // can't buy tons of stuff when carrying a specialCargo
|
|
|
|
if ((available_units == 0)||(price_per_unit > credits)||((unit == 0)&&(current_cargo >= max_cargo))) return NO;
|
|
{
|
|
NSMutableArray* manifest = [NSMutableArray arrayWithArray:shipCommodityData];
|
|
NSMutableArray* manifest_commodity = [NSMutableArray arrayWithArray:(NSArray *)[manifest objectAtIndex:index]];
|
|
NSMutableArray* market_commodity = [NSMutableArray arrayWithArray:(NSArray *)[localMarket objectAtIndex:index]];
|
|
int manifest_quantity = [(NSNumber *)[manifest_commodity objectAtIndex:MARKET_QUANTITY] intValue];
|
|
int market_quantity = [(NSNumber *)[market_commodity objectAtIndex:MARKET_QUANTITY] intValue];
|
|
manifest_quantity++;
|
|
market_quantity--;
|
|
credits -= price_per_unit;
|
|
if (unit == UNITS_TONS)
|
|
current_cargo++;
|
|
[manifest_commodity replaceObjectAtIndex:MARKET_QUANTITY withObject:[NSNumber numberWithInt:manifest_quantity]];
|
|
[market_commodity replaceObjectAtIndex:MARKET_QUANTITY withObject:[NSNumber numberWithInt:market_quantity]];
|
|
[manifest replaceObjectAtIndex:index withObject:[NSArray arrayWithArray:manifest_commodity]];
|
|
[localMarket replaceObjectAtIndex:index withObject:[NSArray arrayWithArray:market_commodity]];
|
|
|
|
[shipCommodityData release];
|
|
shipCommodityData = [[NSArray arrayWithArray:manifest] retain];
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL) trySellingCommodity:(int) index
|
|
{
|
|
NSMutableArray* localMarket;
|
|
if (status == STATUS_DOCKED)
|
|
{
|
|
if (docked_station == nil)
|
|
docked_station = [universe station];
|
|
if ([docked_station localMarket])
|
|
localMarket = [docked_station localMarket];
|
|
else
|
|
localMarket = [docked_station initialiseLocalMarketWithSeed:system_seed andRandomFactor:market_rnd];
|
|
}
|
|
else
|
|
{
|
|
return NO; // can't sell if not docked
|
|
}
|
|
int available_units = [(NSNumber *)[(NSArray *)[shipCommodityData objectAtIndex:index] objectAtIndex:MARKET_QUANTITY] intValue];
|
|
int price_per_unit = [(NSNumber *)[(NSArray *)[localMarket objectAtIndex:index] objectAtIndex:MARKET_PRICE] intValue];
|
|
if (available_units == 0) return NO;
|
|
{
|
|
NSMutableArray* manifest = [NSMutableArray arrayWithArray:shipCommodityData];
|
|
NSMutableArray* manifest_commodity = [NSMutableArray arrayWithArray:(NSArray *)[manifest objectAtIndex:index]];
|
|
NSMutableArray* market_commodity = [NSMutableArray arrayWithArray:(NSArray *)[localMarket objectAtIndex:index]];
|
|
int manifest_quantity = [(NSNumber *)[manifest_commodity objectAtIndex:MARKET_QUANTITY] intValue];
|
|
int market_quantity = [(NSNumber *)[market_commodity objectAtIndex:MARKET_QUANTITY] intValue];
|
|
// check the market's not flooded
|
|
if (market_quantity >= 127)
|
|
return NO;
|
|
manifest_quantity--;
|
|
market_quantity++;
|
|
credits += price_per_unit;
|
|
[manifest_commodity replaceObjectAtIndex:MARKET_QUANTITY withObject:[NSNumber numberWithInt:manifest_quantity]];
|
|
[market_commodity replaceObjectAtIndex:MARKET_QUANTITY withObject:[NSNumber numberWithInt:market_quantity]];
|
|
[manifest replaceObjectAtIndex:index withObject:[NSArray arrayWithArray:manifest_commodity]];
|
|
[localMarket replaceObjectAtIndex:index withObject:[NSArray arrayWithArray:market_commodity]];
|
|
[shipCommodityData release];
|
|
shipCommodityData = [[NSArray arrayWithArray:manifest] retain];
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL) isMining
|
|
{
|
|
return using_mining_laser;
|
|
}
|
|
|
|
- (BOOL) speech_on
|
|
{
|
|
return speech_on;
|
|
}
|
|
|
|
// new extra equipment routines
|
|
- (BOOL) has_extra_equipment:(NSString *) eq_key
|
|
{
|
|
if ([extra_equipment objectForKey:eq_key])
|
|
return YES;
|
|
else
|
|
return NO;
|
|
}
|
|
|
|
- (void) add_extra_equipment:(NSString *) eq_key
|
|
{
|
|
[extra_equipment setObject:[NSNumber numberWithBool:YES] forKey:eq_key];
|
|
[self set_flags_from_extra_equipment];
|
|
}
|
|
|
|
- (void) remove_extra_equipment:(NSString *) eq_key
|
|
{
|
|
if ([extra_equipment objectForKey:eq_key])
|
|
[extra_equipment removeObjectForKey:eq_key];
|
|
[self set_flags_from_extra_equipment];
|
|
}
|
|
|
|
- (void) set_extra_equipment_from_flags
|
|
{
|
|
int original_hold_size = [universe maxCargoForShip:ship_desc];
|
|
//
|
|
if (max_cargo > original_hold_size)
|
|
[self add_extra_equipment:@"EQ_CARGO_BAY"];
|
|
if (has_escape_pod)
|
|
[self add_extra_equipment:@"EQ_ESCAPE_POD"];
|
|
if (has_scoop)
|
|
[self add_extra_equipment:@"EQ_FUEL_SCOOPS"];
|
|
if (has_fuel_injection)
|
|
[self add_extra_equipment:@"EQ_FUEL_INJECTION"];
|
|
if (has_ecm)
|
|
[self add_extra_equipment:@"EQ_ECM"];
|
|
if (has_energy_bomb)
|
|
[self add_extra_equipment:@"EQ_ENERGY_BOMB"];
|
|
if (has_energy_unit)
|
|
{
|
|
switch (energy_unit)
|
|
{
|
|
case ENERGY_UNIT_NORMAL :
|
|
[self add_extra_equipment:@"EQ_ENERGY_UNIT"];
|
|
break;
|
|
case ENERGY_UNIT_NAVAL :
|
|
[self add_extra_equipment:@"EQ_NAVAL_ENERGY_UNIT"];
|
|
break;
|
|
}
|
|
}
|
|
if (has_docking_computer)
|
|
[self add_extra_equipment:@"EQ_DOCK_COMP"];
|
|
if (has_galactic_hyperdrive)
|
|
[self add_extra_equipment:@"EQ_GAL_DRIVE"];
|
|
|
|
if (shield_booster > 1)
|
|
[self add_extra_equipment:@"EQ_SHIELD_BOOSTER"];
|
|
if (shield_enhancer)
|
|
[self add_extra_equipment:@"EQ_NAVAL_SHIELD_BOOSTER"];
|
|
}
|
|
|
|
- (void) set_flags_from_extra_equipment
|
|
{
|
|
int original_hold_size = [universe maxCargoForShip:ship_desc];
|
|
//
|
|
if ([self has_extra_equipment:@"EQ_CARGO_BAY"])
|
|
max_cargo = original_hold_size + 15 - max_passengers * 5;
|
|
//
|
|
has_escape_pod = [self has_extra_equipment:@"EQ_ESCAPE_POD"];
|
|
has_scoop = [self has_extra_equipment:@"EQ_FUEL_SCOOPS"];
|
|
has_fuel_injection = [self has_extra_equipment:@"EQ_FUEL_INJECTION"];
|
|
has_ecm = [self has_extra_equipment:@"EQ_ECM"];
|
|
has_energy_bomb = [self has_extra_equipment:@"EQ_ENERGY_BOMB"];
|
|
has_docking_computer = [self has_extra_equipment:@"EQ_DOCK_COMP"];
|
|
has_galactic_hyperdrive = [self has_extra_equipment:@"EQ_GAL_DRIVE"];
|
|
has_cloaking_device = [self has_extra_equipment:@"EQ_CLOAKING_DEVICE"];
|
|
|
|
has_energy_unit = ([self has_extra_equipment:@"EQ_ENERGY_UNIT"]||[self has_extra_equipment:@"EQ_NAVAL_ENERGY_UNIT"]);
|
|
if (has_energy_unit)
|
|
energy_unit = ([self has_extra_equipment:@"EQ_NAVAL_ENERGY_UNIT"])? ENERGY_UNIT_NAVAL : ENERGY_UNIT_NORMAL;
|
|
else
|
|
energy_unit = ENERGY_UNIT_NONE;
|
|
|
|
if ([self has_extra_equipment:@"EQ_ADVANCED_COMPASS"])
|
|
compass_mode = COMPASS_MODE_PLANET;
|
|
else
|
|
compass_mode = COMPASS_MODE_BASIC;
|
|
|
|
shield_booster = ([self has_extra_equipment:@"EQ_SHIELD_BOOSTER"])? 2:1;
|
|
shield_enhancer = ([self has_extra_equipment:@"EQ_NAVAL_SHIELD_BOOSTER"])? 1:0;
|
|
}
|
|
|
|
|
|
// time delay method for playing afterburner sounds
|
|
// this overlaps two sounds each 2 seconds long, but with a .5s
|
|
// crossfade
|
|
NSSound* burnersound;
|
|
- (void) loopAfterburnerSound
|
|
{
|
|
SEL _loopAfterburnerSoundSelector = @selector(loopAfterburnerSound);
|
|
|
|
if (!afterburner_engaged) // end the loop cycle
|
|
{
|
|
afterburnerSoundLooping = NO;
|
|
return;
|
|
}
|
|
|
|
afterburnerSoundLooping = YES;
|
|
|
|
if (burnersound == afterburner1Sound)
|
|
burnersound = afterburner2Sound;
|
|
else
|
|
burnersound = afterburner1Sound;
|
|
|
|
// NSLog(@"DEBUG loopAfterburnerSound playing sound %@", burnersound);
|
|
#ifdef HAVE_SOUND
|
|
[burnersound play];
|
|
#endif
|
|
[self performSelector:_loopAfterburnerSoundSelector
|
|
withObject:NULL
|
|
afterDelay:1.25]; // and swap sounds in 1.25s time
|
|
}
|
|
|
|
- (void) stopAfterburnerSound
|
|
{
|
|
[burnersound stop];
|
|
}
|
|
|
|
// ***JESTER_START*** 11/08/04
|
|
#ifndef GNUSTEP
|
|
NSString* GenerateDisplayString(int inModeWidth, int inModeHeight, int inModeRefresh)
|
|
{
|
|
NSString *displayModeString = nil;
|
|
if(inModeRefresh != 0)
|
|
{
|
|
displayModeString = [NSString stringWithFormat:@" Fullscreen: %d x %d at %d Hz ", inModeWidth, inModeHeight, inModeRefresh];
|
|
}
|
|
else
|
|
{
|
|
//Let's not bother showing the useless modeRefresh info on Powerbooks that don't have refresh info.
|
|
displayModeString = [NSString stringWithFormat:@" Fullscreen: %d x %d ", inModeWidth, inModeHeight];
|
|
}
|
|
return displayModeString;
|
|
}
|
|
#endif
|
|
// ***JESTER_END*** 11/08/04
|
|
|
|
- (void) setScript_target:(ShipEntity *)ship
|
|
{
|
|
script_target = ship;
|
|
}
|
|
|
|
- (ShipEntity*) script_target
|
|
{
|
|
return script_target;
|
|
}
|
|
|
|
- (BOOL) hasHostileTarget
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
- (void) receiveCommsMessage:(NSString *) message_text
|
|
{
|
|
[universe addCommsMessage:message_text forCount:4.5];
|
|
}
|
|
|
|
- (void) getFined
|
|
{
|
|
if (legal_status == 0)
|
|
return; // nothing to pay for
|
|
int local_gov = [(NSNumber*)[[universe currentSystemData] objectForKey:KEY_GOVERNMENT] intValue];
|
|
int fine = 50 + ((local_gov < 2)||(local_gov > 5))? 50:0;
|
|
fine *= legal_status;
|
|
if (fine > credits)
|
|
{
|
|
int payback = legal_status * credits / fine;
|
|
legal_status -= payback;
|
|
credits = 0;
|
|
}
|
|
else
|
|
{
|
|
legal_status = 0;
|
|
credits -= fine;
|
|
}
|
|
NSString* fined_message = [NSString stringWithFormat:[universe expandDescription:@"[fined]" forSystem:system_seed], fine];
|
|
[universe addMessage:fined_message forCount:6];
|
|
ship_clock_adjust = 24 * 3600; // take up a day
|
|
if (gui_screen = GUI_SCREEN_STATUS)
|
|
[self setGuiToStatusScreen];
|
|
}
|
|
|
|
- (BOOL) checkPerPolyCollisionWithShip:(ShipEntity *)other // overrides the ShipEntity version
|
|
{
|
|
// NSLog(@"DEBUG checking per poly collision Player versus %@ %d", [other name], [other universal_id]);
|
|
|
|
// This is not currently working so...
|
|
return YES;
|
|
|
|
Quaternion q_actual = q_rotation;
|
|
q_actual.w = -q_actual.w; // reverse rotation
|
|
|
|
gl_matrix rMatrix;
|
|
quaternion_into_gl_matrix( q_actual, rMatrix);
|
|
|
|
// DEBUG - TEMPORARY
|
|
// return YES;
|
|
|
|
// check each surface versus the other's particle cloud ...
|
|
//
|
|
int f;
|
|
BOOL all_clear = YES;
|
|
int surfs_hit = 0;
|
|
Vector incidence = make_vector( 0, 0, 0);
|
|
Vector direction = make_vector( 0, 0, 0);
|
|
for (f = 0; f < n_faces; f++)
|
|
{
|
|
face_hit[f] = NO;
|
|
|
|
Vector v0 = vertices[faces[f].vertex[0]];
|
|
Vector v1 = vertices[faces[f].vertex[1]];
|
|
Vector v2 = vertices[faces[f].vertex[2]];
|
|
mult_vector_gl_matrix( &v0, rMatrix);
|
|
mult_vector_gl_matrix( &v1, rMatrix);
|
|
mult_vector_gl_matrix( &v2, rMatrix);
|
|
|
|
Vector vi = make_vector(v1.x - v0.x, v1.y - v0.y, v1.z - v0.z);
|
|
Vector vj = make_vector(v2.x - v0.x, v2.y - v0.y, v2.z - v0.z);
|
|
|
|
Vector vs = faces[f].normal;
|
|
mult_vector_gl_matrix( &vs, rMatrix);
|
|
|
|
Vector p0 = make_vector( position.x + v0.x, position.y + v0.y, position.z + v0.z);
|
|
|
|
// get bounding box relative to this surface's orientation
|
|
BoundingBox arbb = [other findBoundingBoxRelativeToPosition:p0 InVectors: vi : vj : vs];
|
|
|
|
if ((arbb.max_x < 0.0) // all p.vi < 0
|
|
||(arbb.min_x > 1.0) // all p.vi > 1
|
|
||(arbb.max_y < 0.0) // all p.vj < 0
|
|
||(arbb.min_y > 1.0) // all p.vj > 1
|
|
||(arbb.min_x + arbb.min_y > 1.0) // all p.vi + p.vj > 1
|
|
||(arbb.min_z > 0.0) // all p.vs > 0
|
|
||(arbb.max_z < 0.0)) // all p.vs < 0
|
|
continue; // this surface doesn't intersect the point cloud;
|
|
else
|
|
{
|
|
// this surface intersects the point cloud
|
|
incidence.x += vs.x; incidence.y += vs.y; incidence.z += vs.z;
|
|
|
|
Vector dir = make_vector( v0.x + v1.x + v2.x, v0.y + v1.y + v2.y, v0.z + v1.z + v2.z);
|
|
dir = unit_vector(&dir);
|
|
direction.x += dir.x; direction.y += dir.y; direction.z += dir.z;
|
|
|
|
face_hit[f] = YES;
|
|
all_clear = NO;
|
|
surfs_hit++;
|
|
}
|
|
}
|
|
if (!all_clear)
|
|
{
|
|
collision_vector = unit_vector(&incidence);
|
|
if (isnan(collision_vector.x)||isnan(collision_vector.y)||isnan(collision_vector.z))
|
|
collision_vector = unit_vector(&direction);
|
|
|
|
NSLog( @"DEBUG Player Ship %@ %d versus other %@ %d collision, %d surfaces intersected, incidence [%.3f, %.3f, %.3f]",
|
|
name, universal_id, [other name], [other universal_id],
|
|
surfs_hit, collision_vector.x, collision_vector.y, collision_vector.z);
|
|
|
|
[collisionVectorForEntity
|
|
setObject:[NSArray arrayWithObjects: [NSNumber numberWithFloat:collision_vector.x],
|
|
[NSNumber numberWithFloat:collision_vector.y],
|
|
[NSNumber numberWithFloat:collision_vector.z], nil]
|
|
forKey:[NSString stringWithFormat:@"%@", other]];
|
|
|
|
return YES;
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL) checkPerPolyCollisionWithParticle:(ParticleEntity *)other
|
|
{
|
|
// NSLog(@"DEBUG checking per poly collision %@ %d versus particle", name, universal_id);
|
|
|
|
|
|
// This is not currently working so...
|
|
//
|
|
return YES;
|
|
//
|
|
////
|
|
|
|
if (!other)
|
|
return NO;
|
|
|
|
Quaternion q_actual = q_rotation;
|
|
q_actual.w = -q_actual.w;
|
|
|
|
gl_matrix rMatrix;
|
|
quaternion_into_gl_matrix( q_actual, rMatrix);
|
|
|
|
// check bounding boxes ...
|
|
//
|
|
// get position relative to this ship's orientation
|
|
Vector o_pos = other->position;
|
|
o_pos.x -= position.x; o_pos.y -= position.y; o_pos.z -= position.z;
|
|
double cr = other->collision_radius;
|
|
|
|
int f;
|
|
BOOL all_clear = YES;
|
|
int surfs_hit = 0;
|
|
Vector incidence = make_vector( 0, 0, 0);
|
|
Vector direction = make_vector( 0, 0, 0);
|
|
for (f = 0; f < n_faces; f++)
|
|
{
|
|
Vector v0 = vertices[faces[f].vertex[0]];
|
|
Vector v1 = vertices[faces[f].vertex[1]];
|
|
Vector v2 = vertices[faces[f].vertex[2]];
|
|
|
|
mult_vector_gl_matrix(&v0, rMatrix);
|
|
mult_vector_gl_matrix(&v1, rMatrix);
|
|
mult_vector_gl_matrix(&v2, rMatrix);
|
|
|
|
Vector vs = faces[f].normal;
|
|
mult_vector_gl_matrix(&vs, rMatrix);
|
|
|
|
Vector q0 = make_vector( o_pos.x - v0.x, o_pos.y - v0.y, o_pos.z - v0.z);
|
|
GLfloat dist = dot_product( q0, vs);
|
|
|
|
if (dist < cr) // p2 inside sphere
|
|
{
|
|
// this surface intersects the sphere
|
|
incidence.x += vs.x; incidence.y += vs.y; incidence.z += vs.z;
|
|
|
|
Vector dir = make_vector( v0.x + v1.x + v2.x, v0.y + v1.y + v2.y, v0.z + v1.z + v2.z);
|
|
dir = unit_vector(&dir);
|
|
direction.x += dir.x; direction.y += dir.y; direction.z += dir.z;
|
|
|
|
all_clear = NO;
|
|
surfs_hit++;
|
|
}
|
|
|
|
}
|
|
if (!all_clear)
|
|
{
|
|
collision_vector = unit_vector(&incidence);
|
|
if (isnan(collision_vector.x)||isnan(collision_vector.y)||isnan(collision_vector.z))
|
|
collision_vector = unit_vector(&direction);
|
|
|
|
// NSLog( @"Ship %@ %d versus particle collision, %d surfaces intersected, incidence [%.3f, %.3f, %.3f]",
|
|
// name, universal_id, surfs_hit, collision_vector.x, collision_vector.y, collision_vector.z);
|
|
|
|
[collisionVectorForEntity
|
|
setObject:[NSArray arrayWithObjects: [NSNumber numberWithFloat:collision_vector.x],
|
|
[NSNumber numberWithFloat:collision_vector.y],
|
|
[NSNumber numberWithFloat:collision_vector.z], nil]
|
|
forKey:[NSString stringWithFormat:@"%@", other]];
|
|
|
|
return YES;
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
@end
|