Most AI reactToMessage: calls now also have a script event; see http://www.aegidian.org/bb/viewtopic.php?p=47620#47620 . Some cleanup and optimization. Added command-line hack to graph difference between Vector.random() and Vector.randomDirectionAndLength() as in http://wiki.alioth.net/index.php/Image:Randomvectordistribution.png .

git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@1423 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Jens Ayton 2008-02-26 01:54:26 +00:00
parent 0d0681de10
commit e95e3fd521
20 changed files with 622 additions and 333 deletions

View File

@ -997,7 +997,7 @@
083325DC09DDBCDE00F5B8E4 /* OOColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOColor.m; sourceTree = "<group>"; };
083DB4D30A70E51E00B419B2 /* OOBrain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOBrain.h; sourceTree = "<group>"; };
083DB4D40A70E51E00B419B2 /* OOBrain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOBrain.m; sourceTree = "<group>"; };
0865432206B8447D000CA0AB /* OoliteDev.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OoliteDev.app; sourceTree = BUILT_PRODUCTS_DIR; };
0865432206B8447D000CA0AB /* Oolite.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Oolite.app; sourceTree = BUILT_PRODUCTS_DIR; };
0878FD2F086EF845004CB752 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
1A020E0A0D020AFB00C3F51E /* changedScriptHandlers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = changedScriptHandlers.plist; sourceTree = "<group>"; };
@ -1649,7 +1649,7 @@
19C28FACFE9D520D11CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
0865432206B8447D000CA0AB /* OoliteDev.app */,
0865432206B8447D000CA0AB /* Oolite.app */,
1A71E6F30BCE340C00CD5C13 /* libpng.a */,
);
name = Products;
@ -2847,7 +2847,7 @@
name = Oolite;
productInstallPath = "$(HOME)/Applications";
productName = Oolite;
productReference = 0865432206B8447D000CA0AB /* OoliteDev.app */;
productReference = 0865432206B8447D000CA0AB /* Oolite.app */;
productType = "com.apple.product-type.application";
};
1A71E6F20BCE340C00CD5C13 /* libpng-custom */ = {

View File

@ -332,9 +332,10 @@ typedef struct
{
if (currentState != nil)
{
SEL _interpretAIMessageSel = @selector(interpretAIMessage:);
if ([owner respondsToSelector:_interpretAIMessageSel])
[owner performSelector:_interpretAIMessageSel withObject:message];
if ([owner respondsToSelector:@selector(interpretAIMessage:)])
{
[owner performSelector:@selector(interpretAIMessage:) withObject:message];
}
}
}

View File

@ -890,7 +890,9 @@ FAIL:
{
Entity *e2 = [targets objectAtIndex:i];
if (e2->isShip)
[[(ShipEntity *)e2 getAI] reactToMessage:@"ECM"];
{
[(ShipEntity *)e2 doScriptEvent:@"shipHitByECM" andReactToAIMessage:@"ECM"];
}
}
}
activation_time += 0.5; // go off every half second

View File

@ -473,7 +473,7 @@ typedef enum
isSpeechOn: 1,
keyboardRollPitchOverride: 1,
waitingForStickCallback: 1;
waitingForStickCallback: 1;
// Note: joystick stuff does nothing under OS X.
// Keeping track of joysticks
@ -615,6 +615,8 @@ typedef enum
- (void) setGuiToIntro1Screen;
- (void) setGuiToIntro2Screen;
- (void) noteGuiChangeFrom:(OOGUIScreenID)fromScreen to:(OOGUIScreenID)toScreen;
- (OOGUIScreenID) guiScreen;
- (void) buySelectedItem;

View File

@ -1279,10 +1279,13 @@ double scoopSoundPlayTime = 0.0;
there turned out to be complications. See mailing list archive.
-- Ahruman 20070802
*/
if ([self alertCondition] != lastScriptAlertCondition)
OOAlertCondition cond = [self alertCondition];
if (cond != lastScriptAlertCondition)
{
[self doScriptEvent:@"alertConditionChanged"];
lastScriptAlertCondition = [self alertCondition];
[self doScriptEvent:@"alertConditionChanged"
withArgument:[NSNumber numberWithInt:cond]
andArgument:[NSNumber numberWithInt:lastScriptAlertCondition]];
lastScriptAlertCondition = cond;
}
if (scoopsActive)
@ -2717,7 +2720,7 @@ double scoopSoundPlayTime = 0.0;
Quaternion q1 = orientation;
q1.w = -q1.w; // player view is reversed remember!
Entity *target = [self primaryTarget];
ShipEntity *target = [self primaryTarget];
// select a new active missile and decrease the missiles count
missile_entity[activeMissile] = nil;
@ -2757,9 +2760,10 @@ double scoopSoundPlayTime = 0.0;
[UNIVERSE addEntity:missile];
[missile release];
[(ShipEntity *)target setPrimaryAggressor:self];
[[(ShipEntity *)target getAI] reactToMessage:@"INCOMING_MISSILE"];
[target setPrimaryAggressor:self];
[target doScriptEvent:@"shipAttackedWithMissile" withArgument:missile andArgument:self];
[target reactToAIMessage:@"INCOMING_MISSILE"];
[UNIVERSE playCustomSound:@"[missile-launched]"];
@ -2957,9 +2961,10 @@ double scoopSoundPlayTime = 0.0;
if (status == STATUS_DEAD) return;
if (amount == 0.0) return;
[ent retain];
[other retain];
[[ent retain] autorelease];
[[other retain] autorelease];
rel_pos = (ent != nil) ? [ent position] : kZeroVector;
rel_pos = vector_subtract(rel_pos, position);
@ -3018,25 +3023,17 @@ double scoopSoundPlayTime = 0.0;
if (energy <= 0.0) //use normal ship temperature calculations for heat damage
{
if ((other)&&(other->isShip))
if ([other isShip])
{
ShipEntity* hunter = (ShipEntity *)other;
[hunter collectBountyFor:self];
if ([hunter primaryTarget] == (Entity *)self)
{
[hunter removeTarget:(Entity *)self];
[[hunter getAI] message:@"TARGET_DESTROYED"];
}
[(ShipEntity *)other noteTargetDestroyed:self];
}
[self getDestroyedBy:other context:@"energy damage"];
}
if (internal_damage) [self takeInternalDamage];
[ent release];
[other release];
else
{
if (internal_damage) [self takeInternalDamage];
}
}
@ -3049,14 +3046,10 @@ double scoopSoundPlayTime = 0.0;
if (status == STATUS_DEAD)
return;
[ent retain];
rel_pos = (ent)? ent->position : kZeroVector;
rel_pos.x -= position.x;
rel_pos.y -= position.y;
rel_pos.z -= position.z;
d_forward = dot_product(rel_pos, v_forward);
[[ent retain] autorelease];
rel_pos = ent ? [ent position] : kZeroVector;
rel_pos = vector_subtract(rel_pos, position);
d_forward = dot_product(rel_pos, v_forward);
if (scrapeDamageSound)
{
@ -3089,31 +3082,27 @@ double scoopSoundPlayTime = 0.0;
amount = 0.0;
}
}
if (amount)
{
internal_damage = ((ranrot_rand() & PLAYER_INTERNAL_DAMAGE_FACTOR) < amount); // base chance of damage to systems
}
energy -= amount;
if (energy <= 0.0)
{
if ((ent)&&(ent->isShip))
if ([ent isShip])
{
ShipEntity* hunter = (ShipEntity *)ent;
[hunter collectBountyFor:self];
if ([hunter primaryTarget] == (Entity *)self)
{
[hunter removeTarget:(Entity *)self];
[[hunter getAI] message:@"TARGET_DESTROYED"];
}
[(ShipEntity *)ent noteTargetDestroyed:self];
}
[self getDestroyedBy:ent context:@"scrape damage"];
}
if (internal_damage) [self takeInternalDamage];
[ent release];
if (internal_damage)
{
[self takeInternalDamage];
}
}
@ -3504,12 +3493,14 @@ double scoopSoundPlayTime = 0.0;
ShipEntity* ship = (ShipEntity *)thing;
if (self == [ship primaryTarget])
{
[[ship getAI] message:@"TARGET_LOST"];
[ship noteLostTarget];
}
}
}
for (i = 0; i < ent_count; i++)
{
[my_entities[i] release]; // released
}
}
@ -3997,9 +3988,10 @@ double scoopSoundPlayTime = 0.0;
[lastTextKey release];
lastTextKey = nil;
}
OOGUIScreenID oldScreen = gui_screen;
gui_screen = GUI_SCREEN_STATUS;
[self setShowDemoShips: NO];
[UNIVERSE setDisplayText: YES];
[UNIVERSE setDisplayCursor: NO];
@ -4014,6 +4006,8 @@ double scoopSoundPlayTime = 0.0;
[self setShowDemoShips: YES];
// END TEST
#endif
[self noteGuiChangeFrom:oldScreen to:gui_screen];
}
@ -4107,14 +4101,14 @@ double scoopSoundPlayTime = 0.0;
{
NSDictionary* targetSystemData;
NSString* targetSystemName;
targetSystemData = [[UNIVERSE generateSystemData:target_system_seed] retain]; // retained
targetSystemName = [[UNIVERSE getSystemName:target_system_seed] retain]; // retained
BOOL sunGoneNova = NO;
if ([targetSystemData objectForKey:@"sun_gone_nova"])
sunGoneNova = YES;
// GUI stuff
{
GuiDisplayGen* gui = [UNIVERSE gui];
@ -4170,26 +4164,26 @@ double scoopSoundPlayTime = 0.0;
}
/* ends */
if (lastTextKey)
{
[lastTextKey release];
lastTextKey = nil;
}
[lastTextKey release];
lastTextKey = nil;
[targetSystemData release];
[targetSystemName release];
OOGUIScreenID oldScreen = gui_screen;
gui_screen = GUI_SCREEN_SYSTEM_DATA;
[self setShowDemoShips: NO];
[UNIVERSE setDisplayText: YES];
[UNIVERSE setDisplayCursor: NO];
[UNIVERSE setViewDirection: VIEW_GUI_DISPLAY];
[UNIVERSE removeDemoShips];
[self setBackgroundFromDescriptionsKey:@"gui-scene-show-planet"];
[self noteGuiChangeFrom:oldScreen to:gui_screen];
if (oldScreen != gui_screen) [self checkScript];
}
@ -4250,15 +4244,18 @@ double scoopSoundPlayTime = 0.0;
[gui setCurrentRow:16];
}
/* ends */
OOGUIScreenID oldScreen = gui_screen;
gui_screen = GUI_SCREEN_LONG_RANGE_CHART;
[targetSystemName release];
[self setShowDemoShips: NO];
[UNIVERSE setDisplayText: YES];
[UNIVERSE setDisplayCursor: YES];
[UNIVERSE setViewDirection: VIEW_GUI_DISPLAY];
[self noteGuiChangeFrom:oldScreen to:gui_screen];
}
@ -4290,21 +4287,21 @@ double scoopSoundPlayTime = 0.0;
[gui setShowTextCursor:NO];
}
/* ends */
OOGUIScreenID oldScreen = gui_screen;
gui_screen = GUI_SCREEN_SHORT_RANGE_CHART;
[targetSystemName release]; // released
[self setShowDemoShips: NO];
[UNIVERSE setDisplayText: YES];
[UNIVERSE setDisplayCursor: YES];
[UNIVERSE setViewDirection: VIEW_GUI_DISPLAY];
[self noteGuiChangeFrom:oldScreen to:gui_screen];
}
- (void) setGuiToGameOptionsScreen
{
#ifdef GNUSTEP
@ -5022,9 +5019,9 @@ static int last_outfitting_index;
- (void) setGuiToIntro2Screen
{
NSString *text;
NSString *text = nil;
GuiDisplayGen* gui = [UNIVERSE gui];
[gui clear];
[gui setTitle:@"Oolite"];
@ -5033,12 +5030,11 @@ static int last_outfitting_index;
[gui setColor:[OOColor yellowColor] forRow:21];
[gui setShowTextCursor:NO];
[UNIVERSE set_up_intro2];
if (gui)
gui_screen = GUI_SCREEN_INTRO2;
if (gui) gui_screen = GUI_SCREEN_INTRO2;
[self setShowDemoShips: YES];
[UNIVERSE setDisplayText: YES];
[UNIVERSE setDisplayCursor: NO];
@ -5046,6 +5042,17 @@ static int last_outfitting_index;
}
- (void) noteGuiChangeFrom:(OOGUIScreenID)fromScreen to:(OOGUIScreenID)toScreen
{
if (fromScreen != toScreen)
{
[self doScriptEvent:@"guiScreenChanged"
withArgument:GUIScreenIDToString(toScreen)
andArgument:GUIScreenIDToString(fromScreen)];
}
}
- (void) buySelectedItem
{
GuiDisplayGen* gui = [UNIVERSE gui];
@ -5053,7 +5060,7 @@ static int last_outfitting_index;
if ([key hasPrefix:@"More:"])
{
int from_item = [(NSString*)[[key componentsSeparatedByString:@":"] objectAtIndex:1] intValue];
int from_item = [[key componentsSeparatedByString:@":"] intAtIndex:1];
[self setGuiToEquipShipScreen:from_item:-1];
if ([gui selectedRow] < 0)
@ -5369,7 +5376,7 @@ static int last_outfitting_index;
// following works whether docked or not
for (i = 0; i < n_commodities; i++)
in_hold[i] = [(NSNumber *)[(NSArray *)[shipCommodityData objectAtIndex:i] objectAtIndex:MARKET_QUANTITY] intValue];
in_hold[i] = [[shipCommodityData arrayAtIndex:i] intAtIndex:MARKET_QUANTITY];
for (i = 0; i < [cargo count]; i++)
{
ShipEntity *container = (ShipEntity *)[cargo objectAtIndex:i];
@ -5380,8 +5387,10 @@ static int last_outfitting_index;
for (i = 0; i < n_commodities; i++)
{
if ([(NSNumber *)[(NSArray *)[shipCommodityData objectAtIndex:i] objectAtIndex:MARKET_UNITS] intValue] == UNITS_TONS)
if ([[shipCommodityData arrayAtIndex:i] intAtIndex:MARKET_UNITS] == UNITS_TONS)
{
current_cargo += in_hold[i];
}
}
}
@ -5493,13 +5502,16 @@ static int last_outfitting_index;
[gui setShowTextCursor:NO];
}
OOGUIScreenID oldScreen = gui_screen;
gui_screen = GUI_SCREEN_MARKET;
[self setShowDemoShips: NO];
[UNIVERSE setDisplayText: YES];
[UNIVERSE setDisplayCursor: (status == STATUS_DOCKED)];
[UNIVERSE setViewDirection: VIEW_GUI_DISPLAY];
[self noteGuiChangeFrom:oldScreen to:gui_screen];
}

View File

@ -685,12 +685,15 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
[gui setShowTextCursor:NO];
}
OOGUIScreenID oldScreen = gui_screen;
gui_screen = GUI_SCREEN_CONTRACTS;
[self setShowDemoShips: NO];
[UNIVERSE setDisplayText: YES];
[UNIVERSE setDisplayCursor: YES];
[UNIVERSE setViewDirection: VIEW_GUI_DISPLAY];
[self noteGuiChangeFrom:oldScreen to:gui_screen];
}
@ -974,12 +977,15 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
lastTextKey = nil;
}
OOGUIScreenID oldScreen = gui_screen;
gui_screen = GUI_SCREEN_MANIFEST;
[self setShowDemoShips: NO];
[UNIVERSE setDisplayText: YES];
[UNIVERSE setDisplayCursor: NO];
[UNIVERSE setViewDirection: VIEW_GUI_DISPLAY];
[self noteGuiChangeFrom:oldScreen to:gui_screen];
}

View File

@ -1380,7 +1380,6 @@ static NSTimeInterval time_last_frame;
{
[gameView clearMouse];
[self setGuiToSystemDataScreen];
[self checkScript];
}
if ([gameView isDown:key_map_home])
{
@ -2405,7 +2404,6 @@ static NSTimeInterval time_last_frame;
if (gui_screen != GUI_SCREEN_SYSTEM_DATA)
{
[self setGuiToSystemDataScreen];
[self checkScript];
}
}
@ -2422,8 +2420,9 @@ static NSTimeInterval time_last_frame;
{
if (!switching_equipship_screens)
{
if (!dockedStation)
dockedStation = [UNIVERSE station];
if (!dockedStation) dockedStation = [UNIVERSE station];
OOGUIScreenID oldScreen = gui_screen;
if ((gui_screen == GUI_SCREEN_EQUIP_SHIP)&&[dockedStation hasShipyard])
{
[gameView clearKeys];
@ -2437,6 +2436,8 @@ static NSTimeInterval time_last_frame;
[self setGuiToEquipShipScreen:0:-1];
[[UNIVERSE gui] setSelectedRow:GUI_ROW_EQUIPMENT_START];
}
[self noteGuiChangeFrom:oldScreen to:gui_screen];
}
switching_equipship_screens = YES;
}

View File

@ -1984,6 +1984,7 @@ static int scriptRandomSeed = -1; // ensure proper random function
[se1 setFuel: PLAYER_MAX_FUEL];
[se1AI setStateMachine:@"exitingTraderAI.plist"];
[se1AI setState:@"EXIT_SYSTEM"];
// FIXME: I don't think the following line does anything meaningful.
[se1AI reactToMessage:[NSString stringWithFormat:@"pauseAI: %d", 3 + (ranrot_rand() & 15)]];
[se1 setPrimaryRole:@"none"]; // prevents new ship from appearing at witchpoint when this one leaves!
}

View File

@ -285,8 +285,10 @@ MA 02110-1301, USA.
// Collision detection
Octree *octree;
#ifndef NDEBUG
// DEBUGGING
OOBehaviour debug_condition;
#endif
uint16_t entity_personality; // Per-entity random number. Exposed to shaders and scripts.
NSDictionary *scriptInfo; // script_info dictionary from shipdata.plist, exposed to scripts.
@ -543,6 +545,9 @@ BOOL class_masslocks(int some_class);
- (id) primaryTarget;
- (int) primaryTargetID;
- (void) noteLostTarget;
- (void) noteTargetDestroyed:(ShipEntity *)target;
- (OOBehaviour) behaviour;
- (void) setBehaviour:(OOBehaviour) cond;
@ -644,15 +649,15 @@ BOOL class_masslocks(int some_class);
- (int) checkShipsInVicinityForWitchJumpExit;
- (BOOL) trackCloseContacts;
- (void) setTrackCloseContacts:(BOOL) value;
- (BOOL) isHulk;
/*
* Changes a ship to a hulk, for example when the pilot ejects.
* Aso unsets hulkiness for example when a new pilot gets in.
*/
- (void) setHulk:(BOOL) isNowHulk;
- (BOOL) isHulk;
- (void) claimAsSalvage;
- (void) sendCoordinatesToPilot;
- (void) pilotArrived;
@ -666,8 +671,13 @@ BOOL class_masslocks(int some_class);
// For the player, they do that and also call doWorldScriptEvent:.
- (void) doScriptEvent:(NSString *)message;
- (void) doScriptEvent:(NSString *)message withArgument:(id)argument;
- (void) doScriptEvent:(NSString *)message withArgument:(id)argument1 andArgument:(id)argument2;
- (void) doScriptEvent:(NSString *)message withArguments:(NSArray *)arguments;
- (void) reactToAIMessage:(NSString *)message;
- (void) doScriptEvent:(NSString *)scriptEvent andReactToAIMessage:(NSString *)aiMessage;
- (void) doScriptEvent:(NSString *)scriptEvent withArgument:(id)argument andReactToAIMessage:(NSString *)aiMessage;
@end

View File

@ -989,7 +989,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
// send AI a message about the touch
int temp_id = primaryTarget;
primaryTarget = other->universalID;
[shipAI reactToMessage:@"CLOSE CONTACT"];
[self doScriptEvent:@"shipCloseContact" withArgument:other andReactToAIMessage:@"CLOSE CONTACT"];
primaryTarget = temp_id;
}
}
@ -1112,12 +1112,10 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
ShipEntity* target = [UNIVERSE entityForUniversalID:primaryTarget];
if ((target)&&(target->scanClass == CLASS_POLICE))
{
primaryTarget = NO_TARGET;
[shipAI reactToMessage:@"TARGET_LOST"];
[self noteLostTarget];
}
}
//
if (trackCloseContacts)
{
// in checkCloseCollisionWith: we check if some thing has come within touch range (origin within our collision_radius)
@ -1141,40 +1139,54 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
int temp_id = primaryTarget;
primaryTarget = other->universalID;
if ((pos0.x < 0.0)&&(pos1.x > 0.0))
[shipAI reactToMessage:@"POSITIVE X TRAVERSE"];
{
[self doScriptEvent:@"shipTraversePositiveX" withArgument:other andReactToAIMessage:@"POSITIVE X TRAVERSE"];
}
if ((pos0.x > 0.0)&&(pos1.x < 0.0))
[shipAI reactToMessage:@"NEGATIVE X TRAVERSE"];
{
[self doScriptEvent:@"shipTraverseNegativeX" withArgument:other andReactToAIMessage:@"NEGATIVE X TRAVERSE"];
}
if ((pos0.y < 0.0)&&(pos1.y > 0.0))
[shipAI reactToMessage:@"POSITIVE Y TRAVERSE"];
{
[self doScriptEvent:@"shipTraversePositiveY" withArgument:other andReactToAIMessage:@"POSITIVE Y TRAVERSE"];
}
if ((pos0.y > 0.0)&&(pos1.y < 0.0))
[shipAI reactToMessage:@"NEGATIVE Y TRAVERSE"];
{
[self doScriptEvent:@"shipTraverseNegativeY" withArgument:other andReactToAIMessage:@"NEGATIVE Y TRAVERSE"];
}
if ((pos0.z < 0.0)&&(pos1.z > 0.0))
[shipAI reactToMessage:@"POSITIVE Z TRAVERSE"];
{
[self doScriptEvent:@"shipTraversePositiveZ" withArgument:other andReactToAIMessage:@"POSITIVE Z TRAVERSE"];
}
if ((pos0.z > 0.0)&&(pos1.z < 0.0))
[shipAI reactToMessage:@"NEGATIVE Z TRAVERSE"];
{
[self doScriptEvent:@"shipTraverseNegativeZ" withArgument:other andReactToAIMessage:@"NEGATIVE Z TRAVERSE"];
}
primaryTarget = temp_id;
[closeContactsInfo removeObjectForKey: other_key];
}
}
else
{
[closeContactsInfo removeObjectForKey: other_key];
}
}
}
// think!
if (brain)
[brain update:delta_t];
[brain update:delta_t];
// super update
//
[super update:delta_t];
#ifndef NDEBUG
// DEBUGGING
if (reportAIMessages && (debug_condition != behaviour))
{
OOLog(kOOLogEntityBehaviourChanged, @"%@ behaviour is now %@", self, BehaviourToString(behaviour));
debug_condition = behaviour;
}
#endif
// update time between shots
//
@ -1303,6 +1315,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
if (energy > maxEnergy)
{
energy = maxEnergy;
[self doScriptEvent:@"shipEnergyBecameFull"];
[shipAI message:@"ENERGY_FULL"];
}
}
@ -1328,30 +1341,26 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
frustration = 0.0;
}
}
//
if (status == STATUS_COCKPIT_DISPLAY)
{
[self applyRoll: delta_t * flightRoll andClimb: delta_t * flightPitch];
GLfloat range2 = 0.1 * distance2(position, destination) / (collision_radius * collision_radius);
if ((range2 > 1.0)||(velocity.z > 0.0)) range2 = 1.0;
position.x += range2 * delta_t * velocity.x;
position.y += range2 * delta_t * velocity.y;
position.z += range2 * delta_t * velocity.z;
// return; // here's our problem!
position = vector_add(position, vector_multiply_scalar(velocity, range2 * delta_t));
}
else
{
double target_speed = maxFlightSpeed;
ShipEntity *target = [UNIVERSE entityForUniversalID:primaryTarget];
if ((target == nil)||(target->scanClass == CLASS_NO_DRAW)||(!target->isShip)||([target isCloaked]))
{
// It's no longer a parrot, it has ceased to be, it has joined the choir invisible...
if (primaryTarget != NO_TARGET)
{
[shipAI reactToMessage:@"TARGET_LOST"];
primaryTarget = NO_TARGET;
[self noteLostTarget];
}
else
{
@ -1549,12 +1558,11 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
{
Entity *source = nil;
[shipAI reactToMessage:@"ATTACKED"];
if ([other isKindOfClass:[ShipEntity class]]) source = other;
else source = from;
[self doScriptEvent:@"beingAttacked" withArgument:source];
[shipAI reactToMessage:@"ATTACKED"];
}
@ -1578,7 +1586,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_idle:(double) delta_t
{
double damping = 0.5 * delta_t;
@ -1601,13 +1610,15 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_tumble:(double) delta_t
{
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_tractored:(double) delta_t
{
double distance = [self rangeToDestination];
@ -1681,7 +1692,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyThrust:delta_t];
thrust = 0.0; // must reset thrust now
}
// //
- (void) behaviour_track_target:(double) delta_t
{
[self trackPrimaryTarget:delta_t:NO];
@ -1690,7 +1702,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_intercept_target:(double) delta_t
{
double range = [self rangeToPrimaryTarget];
@ -1698,12 +1711,14 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
{
desired_speed = maxFlightSpeed;
if (range < desired_range)
{
[shipAI reactToMessage:@"DESIRED_RANGE_ACHIEVED"];
}
desired_speed = maxFlightSpeed * [self trackPrimaryTarget:delta_t:NO];
}
else
{
ShipEntity* target = [UNIVERSE entityForUniversalID:primaryTarget];
ShipEntity* target = [self primaryTarget];
double target_speed = [target speed];
double eta = range / (flightSpeed - target_speed);
double last_success_factor = success_factor;
@ -1723,12 +1738,14 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
{
desired_speed += target_speed;
if (target_speed > maxFlightSpeed)
[shipAI reactToMessage:@"TARGET_LOST"];
{
[self noteLostTarget];
}
}
//
if (target) // check introduced to stop crash at next line
{
destination = target->position; /* HEISENBUG crash here */
destination = target->position;
desired_range = 0.5 * target->collision_radius;
[self trackDestination: delta_t : NO];
}
@ -1754,7 +1771,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_attack_target:(double) delta_t
{
BOOL canBurn = has_fuel_injection && (fuel > 1); // was &&(fuel > 0)
@ -1780,25 +1798,27 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_fly_to_target_six:(double) delta_t
{
BOOL canBurn = has_fuel_injection && (fuel > 1); // was &&(fuel > 0)
double max_available_speed = (canBurn)? maxFlightSpeed * AFTERBURNER_FACTOR : maxFlightSpeed;
double range = [self rangeToPrimaryTarget];
BOOL canBurn = has_fuel_injection && (fuel > 1); // was &&(fuel > 0)
double max_available_speed = (canBurn)? maxFlightSpeed * AFTERBURNER_FACTOR : maxFlightSpeed;
double range = [self rangeToPrimaryTarget];
// deal with collisions and lost targets
//
if (proximity_alert != NO_TARGET)
{
[self avoidCollision];
}
if (range > SCANNER_MAX_RANGE)
{
behaviour = BEHAVIOUR_IDLE;
frustration = 0.0;
[shipAI reactToMessage:@"TARGET_LOST"];
[self noteLostTarget];
}
// control speed
//
BOOL isUsingAfterburner = canBurn && (flightSpeed > maxFlightSpeed);
double slow_down_range = weaponRange * COMBAT_WEAPON_RANGE_FACTOR * ((isUsingAfterburner)? 3.0 * AFTERBURNER_FACTOR : 1.0);
ShipEntity* target = [UNIVERSE entityForUniversalID:primaryTarget];
@ -1807,8 +1827,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
if (range < slow_down_range)
{
desired_speed = OOMax_d(target_speed, 0.4 * maxFlightSpeed);
// avoid head-on collision
//
if ((range < 0.5 * distance)&&(behaviour == BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX))
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
}
@ -1817,7 +1837,6 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
// if within 0.75km of the target's six or twelve then vector in attack
//
if (distance < 750.0)
{
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET;
@ -1843,7 +1862,6 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self trackDestination:delta_t :NO];
// use weaponry
//
int missile_chance = 0;
int rhs = 3.2 / delta_t;
if (rhs) missile_chance = 1 + (ranrot_rand() % rhs);
@ -1851,7 +1869,6 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
double hurt_factor = 16 * pow(energy/maxEnergy, 4.0);
if (missiles > missile_chance * hurt_factor)
{
//NSLog(@"]==> firing missile : missiles %d, missile_chance %d, hurt_factor %.3f", missiles, missile_chance, hurt_factor);
[self fireMissile];
}
[self activateCloakingDevice];
@ -1859,7 +1876,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_attack_mining_target:(double) delta_t
{
double range = [self rangeToPrimaryTarget];
@ -1876,11 +1894,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
}
else
{
if (range > SCANNER_MAX_RANGE)
{
behaviour = BEHAVIOUR_IDLE;
[shipAI reactToMessage:@"TARGET_LOST"];
}
if (range > SCANNER_MAX_RANGE) [self noteLostTarget];
desired_speed = maxFlightSpeed * 0.375;
}
[self trackPrimaryTarget:delta_t:NO];
@ -1888,7 +1902,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_attack_fly_to_target:(double) delta_t
{
BOOL canBurn = has_fuel_injection && (fuel > 1); // was &&(fuel > 0)
@ -1927,7 +1942,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
{
behaviour = BEHAVIOUR_IDLE;
frustration = 0.0;
[shipAI reactToMessage:@"TARGET_LOST"];
[self noteLostTarget];
}
}
@ -1974,7 +1989,6 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
double hurt_factor = 16 * pow(energy/maxEnergy, 4.0);
if (missiles > missile_chance * hurt_factor)
{
//NSLog(@"]==> firing missile : missiles %d, missile_chance %d, hurt_factor %.3f", missiles, missile_chance, hurt_factor);
[self fireMissile];
}
[self activateCloakingDevice];
@ -1982,7 +1996,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_attack_fly_from_target:(double) delta_t
{
double range = [self rangeToPrimaryTarget];
@ -2003,14 +2018,14 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
double hurt_factor = 16 * pow(energy/maxEnergy, 4.0);
if (missiles > missile_chance * hurt_factor)
{
//NSLog(@"]==> firing missile : missiles %d, missile_chance %d, hurt_factor %.3f", missiles, missile_chance, hurt_factor);
[self fireMissile];
}
[self activateCloakingDevice];
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_running_defense:(double) delta_t
{
double range = [self rangeToPrimaryTarget];
@ -2028,10 +2043,11 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_flee_target:(double) delta_t
{
BOOL canBurn = has_fuel_injection && (fuel > 1); // was &&(fuel > 0)
BOOL canBurn = has_fuel_injection && (fuel > 1);
double max_available_speed = (canBurn)? maxFlightSpeed * AFTERBURNER_FACTOR : maxFlightSpeed;
double range = [self rangeToPrimaryTarget];
if (range > desired_range)
@ -2060,19 +2076,25 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_fly_range_from_destination:(double) delta_t
{
double distance = [self rangeToDestination];
if (distance < desired_range)
{
behaviour = BEHAVIOUR_FLY_FROM_DESTINATION;
}
else
{
behaviour = BEHAVIOUR_FLY_TO_DESTINATION;
}
frustration = 0.0;
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_face_destination:(double) delta_t
{
double max_cos = 0.995;
@ -2095,7 +2117,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_formation_form_up:(double) delta_t
{
// get updated destination from owner
@ -2108,7 +2131,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
desired_speed = maxFlightSpeed;
[self behaviour_fly_to_destination: delta_t];
}
// //
- (void) behaviour_fly_to_destination:(double) delta_t
{
double distance = [self rangeToDestination];
@ -2157,7 +2181,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_fly_from_destination:(double) delta_t
{
double distance = [self rangeToDestination];
@ -2179,7 +2204,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_avoid_collision:(double) delta_t
{
double distance = [self rangeToDestination];
@ -2205,7 +2231,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
[self applyThrust:delta_t];
}
// //
- (void) behaviour_track_as_turret:(double) delta_t
{
double aim = [self ballTrackLeadingTarget:delta_t];
@ -2222,7 +2249,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self fireTurretCannon: sqrt(magnitude2(p1)) - cr];
}
}
// //
- (void) behaviour_fly_thru_navpoints:(double) delta_t
{
int navpoint_plus_index = (next_navpoint_index + 1) % number_of_navpoints;
@ -2255,10 +2283,10 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
if (dist2 < desired_range * desired_range)
{
// desired range achieved
[shipAI reactToMessage:@"NAVPOINT_REACHED"];
[self doScriptEvent:@"shipReachedNavPoint" andReactToAIMessage:@"NAVPOINT_REACHED"];
if (navpoint_plus_index == 0)
{
[shipAI reactToMessage:@"ENDPOINT_REACHED"];
[self doScriptEvent:@"shipReachedEndPoint" andReactToAIMessage:@"ENDPOINT_REACHED"];
behaviour = BEHAVIOUR_IDLE;
}
next_navpoint_index = navpoint_plus_index; // loop as required
@ -2306,7 +2334,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self applyThrust:delta_t];
desired_speed = temp;
}
// //
- (void) behaviour_experimental:(double) delta_t
{
double aim = [self ballTrackTarget:delta_t];
@ -2315,8 +2344,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
OOLog(@"behaviour.experimental.foundTarget", @"DEBUG BANG! BANG! BANG!");
}
}
// //
////////////////
// override Entity saveToLastFrame
//
@ -4427,9 +4455,8 @@ BOOL class_masslocks(int some_class)
- (void) removeTarget:(Entity *) targetEntity
{
if (primaryTarget != NO_TARGET)
[shipAI reactToMessage:@"TARGET_LOST"];
primaryTarget = NO_TARGET;
[self noteLostTarget];
if (sub_entities)
{
unsigned i;
@ -4437,7 +4464,9 @@ BOOL class_masslocks(int some_class)
{
Entity* se = [sub_entities objectAtIndex:i];
if (se->isShip)
{
[(ShipEntity *)se removeTarget:targetEntity];
}
}
}
}
@ -4455,6 +4484,29 @@ BOOL class_masslocks(int some_class)
}
- (void) noteLostTarget
{
if (primaryTarget != NO_TARGET)
{
primaryTarget = NO_TARGET;
[self doScriptEvent:@"shipLostTarget"];
[shipAI reactToMessage:@"TARGET_LOST"];
}
}
- (void) noteTargetDestroyed:(ShipEntity *)target
{
[self collectBountyFor:(ShipEntity *)target];
if ([self primaryTarget] == target)
{
[self removeTarget:target];
[self doScriptEvent:@"shipDestroyedTarget" withArgument:target];
[shipAI message:@"TARGET_DESTROYED"];
}
}
- (OOBehaviour) behaviour
{
return behaviour;
@ -4652,7 +4704,7 @@ BOOL class_masslocks(int some_class)
if (!target) // leave now!
{
[shipAI message:@"TARGET_LOST"];
[self noteLostTarget]; // NOTE: was AI message: rather than reactToMessage:
return 0.0;
}
@ -4666,7 +4718,7 @@ BOOL class_masslocks(int some_class)
if (range2 > SCANNER_MAX_RANGE2)
{
[shipAI message:@"TARGET_LOST"];
[self noteLostTarget]; // NOTE: was AI message: rather than reactToMessage:
return 0.0;
}
@ -5736,7 +5788,8 @@ BOOL class_masslocks(int some_class)
if ([missile scanClass] == CLASS_MISSILE)
{
[target_ship setPrimaryAggressor:self];
[[target_ship getAI] reactToMessage:@"INCOMING_MISSILE"];
[target_ship doScriptEvent:@"shipAttackedWithMissile" withArgument:missile andArgument:self];
[target_ship reactToAIMessage:@"INCOMING_MISSILE"];
}
return YES;
@ -6181,12 +6234,12 @@ BOOL class_masslocks(int some_class)
[other setPosition:pos2a];
}
}
// remove self from other's collision list
[[other collisionArray] removeObject:self];
[shipAI reactToMessage:@"COLLISION"];
[self doScriptEvent:@"shipCollided" withArgument:other andReactToAIMessage:@"COLLISION"];
return YES;
}
@ -6488,24 +6541,19 @@ BOOL class_masslocks(int some_class)
// die if I'm out of energy
if (energy <= 0.0)
{
if (hunter != nil)
{
[hunter collectBountyFor:self];
if ([hunter primaryTarget] == self)
{
[hunter removeTarget:self];
[[hunter getAI] message:@"TARGET_DESTROYED"];
}
}
[hunter noteTargetDestroyed:self];
[self getDestroyedBy:other context:@"energy damage"];
}
else
{
// warn if I'm low on energy
if (energy < maxEnergy *0.25)
[shipAI reactToMessage:@"ENERGY_LOW"];
if ((energy < maxEnergy *0.125)&&(has_escape_pod)&&((ranrot_rand() & 3) == 0)) // 25% chance he gets to an escape pod
if (energy < maxEnergy * 0.25)
{
[self doScriptEvent:@"shipEnergyIsLow" andReactToAIMessage:@"ENERGY_LOW"];
}
if (energy < maxEnergy *0.125 && has_escape_pod && (ranrot_rand() & 3) == 0) // 25% chance he gets to an escape pod
{
// TODO: abandoning ship should be split out into a separate method.
has_escape_pod = NO;
[shipAI setStateMachine:@"nullAI.plist"];
@ -6537,23 +6585,19 @@ BOOL class_masslocks(int some_class)
if (energy <= 0.0)
{
being_mined = YES; // same as using a mining laser
if ((ent)&&(ent->isShip))
if ([ent isShip])
{
ShipEntity* hunter = (ShipEntity *)ent;
[hunter collectBountyFor:self];
if ([hunter primaryTarget] == (Entity *)self)
{
[hunter removeTarget:(Entity *)self];
[[hunter getAI] message:@"TARGET_DESTROYED"];
}
[(ShipEntity *)ent noteTargetDestroyed:self];
}
[self getDestroyedBy:ent context:@"scrape damage"];
}
else
{
// warn if I'm low on energy
if (energy < maxEnergy *0.25)
[shipAI message:@"ENERGY_LOW"];
if (energy < maxEnergy * 0.25)
{
[self doScriptEvent:@"shipEnergyIsLow" andReactToAIMessage:@"ENERGY_LOW"];
}
}
}
@ -6576,8 +6620,10 @@ BOOL class_masslocks(int some_class)
else
{
// warn if I'm low on energy
if (energy < maxEnergy *0.25)
[shipAI message:@"ENERGY_LOW"];
if (energy < maxEnergy * 0.25)
{
[self doScriptEvent:@"shipEnergyIsLow" andReactToAIMessage:@"ENERGY_LOW"];
}
}
}
@ -7057,15 +7103,35 @@ int w_space_seed = 1234567;
}
- (void) broadcastHitByLaserFrom:(ShipEntity*) aggressor_ship
static BOOL AuthorityPredicate(Entity *entity, void *parameter)
{
ShipEntity *victim = parameter;
// Select main station, if victim is in aegis
if (entity == [UNIVERSE station] && [victim withinStationAegis])
{
return YES;
}
// Select police units in scanner range
if ([entity scanClass] == CLASS_POLICE &&
distance2([victim position], [entity position]) < SCANNER_MAX_RANGE2)
{
return YES;
}
// Reject others
return NO;
}
- (void) broadcastHitByLaserFrom:(ShipEntity *) aggressor_ship
{
/*-- If you're clean, locates all police and stations in range and tells them OFFENCE_COMMITTED --*/
if (!UNIVERSE)
return;
if (bounty)
return;
if (!aggressor_ship)
return;
if (!UNIVERSE) return;
if (bounty) return;
if (!aggressor_ship) return;
if ( (scanClass == CLASS_NEUTRAL)||
(scanClass == CLASS_STATION)||
(scanClass == CLASS_BUOY)||
@ -7073,25 +7139,20 @@ int w_space_seed = 1234567;
(scanClass == CLASS_MILITARY)||
(scanClass == CLASS_PLAYER)) // only for active ships...
{
int ent_count = UNIVERSE->n_entities;
Entity** uni_entities = UNIVERSE->sortedEntities; // grab the public sorted list
Entity* my_entities[ent_count];
int i;
int ship_count = 0;
StationEntity* mainStation = [UNIVERSE station];
for (i = 0; i < ent_count; i++)
if ((uni_entities[i]->isShip)&&((uni_entities[i]->scanClass == CLASS_POLICE)||(uni_entities[i] == mainStation)))
my_entities[ship_count++] = [uni_entities[i] retain]; // retained
//
for (i = 0; i < ship_count ; i++)
NSArray *authorities = nil;
NSEnumerator *authEnum = nil;
ShipEntity *auth = nil;
authorities = [UNIVERSE findShipsMatchingPredicate:AuthorityPredicate
parameter:self
inRange:-1
ofEntity:nil];
authEnum = [authorities objectEnumerator];
while ((auth = [authEnum nextObject]))
{
ShipEntity* ship = (ShipEntity *)my_entities[i];
if (((ship == mainStation) && ([self withinStationAegis])) || (distance2(position, ship->position) < SCANNER_MAX_RANGE2))
{
[ship setFound_target: aggressor_ship];
[[ship getAI] reactToMessage: @"OFFENCE_COMMITTED"];
}
[my_entities[i] release]; // released
[auth setFound_target:aggressor_ship];
[auth doScriptEvent:@"offenceCommittedNearby" withArgument:aggressor_ship andArgument:self];
[auth reactToAIMessage:@"OFFENCE_COMMITTED"];
}
}
}
@ -7322,21 +7383,25 @@ int w_space_seed = 1234567;
}
- (BOOL) trackCloseContacts
{
return trackCloseContacts;
}
- (void) setTrackCloseContacts:(BOOL) value
{
if (value == trackCloseContacts)
return;
if (value == trackCloseContacts) return;
trackCloseContacts = value;
[closeContactsInfo release];
if (trackCloseContacts)
{
if (closeContactsInfo)
[closeContactsInfo removeAllObjects];
else
closeContactsInfo = [[NSMutableDictionary alloc] init];
closeContactsInfo = [[NSMutableDictionary alloc] init];
}
else
{
[closeContactsInfo release];
closeContactsInfo = nil;
}
}
@ -7537,7 +7602,24 @@ int w_space_seed = 1234567;
- (void) doScriptEvent:(NSString *)message withArgument:(id)argument
{
NSArray *arguments = nil;
if (argument != nil) arguments = [NSArray arrayWithObject:argument];
if (argument == nil) argument = [NSNull null];
arguments = [NSArray arrayWithObject:argument];
[self doScriptEvent:message withArguments:arguments];
}
- (void) doScriptEvent:(NSString *)message
withArgument:(id)argument1
andArgument:(id)argument2
{
NSArray *arguments = nil;
if (argument1 == nil) argument1 = [NSNull null];
if (argument2 == nil) argument2 = [NSNull null];
arguments = [NSArray arrayWithObjects:argument1, argument2, nil];
[self doScriptEvent:message withArguments:arguments];
}
@ -7547,6 +7629,26 @@ int w_space_seed = 1234567;
[script doEvent:message withArguments:arguments];
}
- (void) reactToAIMessage:(NSString *)message
{
[shipAI reactToMessage:message];
}
- (void) doScriptEvent:(NSString *)scriptEvent andReactToAIMessage:(NSString *)aiMessage
{
[self doScriptEvent:scriptEvent];
[self reactToAIMessage:aiMessage];
}
- (void) doScriptEvent:(NSString *)scriptEvent withArgument:(id)argument andReactToAIMessage:(NSString *)aiMessage
{
[self doScriptEvent:scriptEvent withArgument:argument];
[self reactToAIMessage:aiMessage];
}
@end

View File

@ -956,11 +956,7 @@ WormholeEntity* whole;
for (i = 0; i < ent_count; i++) if (uni_entities[i]->isShip)
{
ShipEntity *other = (ShipEntity*)uni_entities[i];
if ([other primaryTarget] == self)
{
[[other getAI] message:@"TARGET_LOST"]; // lose targetting
other->primaryTarget = NO_TARGET;
}
[other removeTarget:self];
}
// now we're just a bunch of alien artefacts!
scanClass = CLASS_CARGO;
@ -1342,8 +1338,7 @@ WormholeEntity* whole;
ShipEntity *ship = [self primaryTarget];
if ((ship == nil) || (ship->status == STATUS_DEAD) || (ship->status == STATUS_DOCKED))
{
primaryTarget = NO_TARGET;
[shipAI reactToMessage:@"TARGET_LOST"];
[self noteLostTarget];
return;
}
[self sendExpandedMessage:message toShip:[self primaryTarget]];
@ -1355,8 +1350,7 @@ WormholeEntity* whole;
ShipEntity *ship = [self primaryTarget];
if ((ship == nil) || (ship->status == STATUS_DEAD) || (ship->status == STATUS_DOCKED))
{
primaryTarget = NO_TARGET;
[shipAI reactToMessage:@"TARGET_LOST"];
[self noteLostTarget];
return;
}
if ([ship markForFines]) [shipAI message:@"TARGET_MARKED"];
@ -1370,8 +1364,7 @@ WormholeEntity* whole;
ShipEntity *ship = [self primaryTarget];
if ((ship == nil) || (ship->status == STATUS_DEAD) || (ship->status == STATUS_DOCKED))
{
primaryTarget = NO_TARGET;
[shipAI reactToMessage:@"TARGET_LOST"];
[self noteLostTarget];
return;
}
NSString* finalValue = ExpandDescriptionForCurrentSystem(valueString); // expand values

View File

@ -29,9 +29,9 @@ MA 02110-1301, USA.
typedef enum
{
STATION_ALERT_LEVEL_GREEN,
STATION_ALERT_LEVEL_YELLOW,
STATION_ALERT_LEVEL_RED
STATION_ALERT_LEVEL_GREEN = ALERT_CONDITION_GREEN,
STATION_ALERT_LEVEL_YELLOW = ALERT_CONDITION_YELLOW,
STATION_ALERT_LEVEL_RED = ALERT_CONDITION_RED
} OOStationAlertLevel;
#define STATION_MAX_POLICE 8
@ -48,7 +48,7 @@ typedef enum
NSMutableArray *launchQueue;
double last_launch_time;
double approach_spacing;
OOStationAlertLevel alert_level;
OOStationAlertLevel alertLevel;
OOUniversalID id_lock[MAX_DOCKING_STAGES]; // ship id's or NO_TARGET's
@ -154,29 +154,23 @@ typedef enum
- (BOOL)hasNPCTraffic;
- (void)setHasNPCTraffic:(BOOL)flag;
- (OOStationAlertLevel) alertLevel;
- (void) setAlertLevel:(OOStationAlertLevel)level signallingScript:(BOOL)signallingScript;
////////////////////////////////////////////////////////////// AI methods...
- (void) increaseAlertLevel;
- (void) decreaseAlertLevel;
- (void) launchPolice;
- (void) launchDefenseShip;
- (void) launchScavenger;
- (void) launchMiner;
/**Lazygun** added the following line*/
- (void) launchPirateShip;
- (void) launchShuttle;
- (void) launchTrader;
- (void) launchEscort;
- (BOOL) launchPatrol;
- (void) launchShipWithRole:(NSString*) role;
@ -186,7 +180,6 @@ typedef enum
- (void) acceptDockingClearanceRequestFrom:(ShipEntity *)other;
- (BOOL) isRotatingStation;
- (BOOL) hasShipyard;
@end

View File

@ -698,6 +698,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
isShip = YES;
isStation = YES;
alertLevel = STATION_ALERT_LEVEL_GREEN;
// ** Set up a the docking port
// Look for subentity specifying position
@ -1222,7 +1223,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
int old_behaviour = [(NSNumber*)[previousCondition objectForKey:@"behaviour"] intValue];
return IsBehaviourHostile(old_behaviour);
}
return IsBehaviourHostile(behaviour)||(alert_level == STATION_ALERT_LEVEL_YELLOW)||(alert_level == STATION_ALERT_LEVEL_RED);
return IsBehaviourHostile(behaviour)||(alertLevel == STATION_ALERT_LEVEL_YELLOW)||(alertLevel == STATION_ALERT_LEVEL_RED);
}
@ -1271,76 +1272,94 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
if (self != [UNIVERSE station]) [super takeHeatDamage:amount];
}
- (OOStationAlertLevel) alertLevel
{
return alertLevel;
}
- (void) setAlertLevel:(OOStationAlertLevel)level signallingScript:(BOOL)signallingScript
{
if (level < STATION_ALERT_LEVEL_GREEN) level = STATION_ALERT_LEVEL_GREEN;
if (level > STATION_ALERT_LEVEL_RED) level = STATION_ALERT_LEVEL_RED;
if (alertLevel != level)
{
OOStationAlertLevel oldLevel = alertLevel;
alertLevel = level;
if (signallingScript)
{
[self doScriptEvent:@"alertConditionChanged"
withArgument:[NSNumber numberWithUnsignedInt:level]
andArgument:[NSNumber numberWithUnsignedInt:oldLevel]];
}
switch (level)
{
case STATION_ALERT_LEVEL_GREEN:
[shipAI reactToMessage:@"GREEN_ALERT"];
break;
case STATION_ALERT_LEVEL_YELLOW:
[shipAI reactToMessage:@"YELLOW_ALERT"];
break;
case STATION_ALERT_LEVEL_RED:
[shipAI reactToMessage:@"RED_ALERT"];
break;
}
}
}
//////////////////////////////////////////////// extra AI routines
- (void) increaseAlertLevel
{
switch (alert_level)
{
case STATION_ALERT_LEVEL_GREEN :
alert_level = STATION_ALERT_LEVEL_YELLOW;
[shipAI reactToMessage:@"YELLOW_ALERT"];
break;
case STATION_ALERT_LEVEL_YELLOW :
alert_level = STATION_ALERT_LEVEL_RED;
[shipAI reactToMessage:@"RED_ALERT"];
break;
case STATION_ALERT_LEVEL_RED:
break;
}
[self setAlertLevel:[self alertLevel] + 1 signallingScript:YES];
}
- (void) decreaseAlertLevel
{
switch (alert_level)
{
case STATION_ALERT_LEVEL_RED :
alert_level = STATION_ALERT_LEVEL_YELLOW;
[shipAI reactToMessage:@"CONDITION_YELLOW"];
break;
case STATION_ALERT_LEVEL_YELLOW :
alert_level = STATION_ALERT_LEVEL_GREEN;
[shipAI reactToMessage:@"CONDITION_GREEN"];
break;
case STATION_ALERT_LEVEL_GREEN:
break;
}
[self setAlertLevel:[self alertLevel] - 1 signallingScript:YES];
}
- (void) launchPolice
{
OOTechLevelID techlevel = [self equivalentTechLevel];
if (techlevel == NSNotFound)
techlevel = 6;
int police_target = primaryTarget;
unsigned i;
OOUniversalID police_target = primaryTarget;
unsigned i;
OOTechLevelID techlevel = [self equivalentTechLevel];
if (techlevel == NSNotFound) techlevel = 6;
for (i = 0; (i < 4)&&(police_launched < max_police) ; i++)
{
ShipEntity *police_ship;
ShipEntity *police_ship = nil;
if (![UNIVERSE entityForUniversalID:police_target])
{
[shipAI reactToMessage:@"TARGET_LOST"];
[self noteLostTarget];
return;
}
if ((Ranrot() & 7) + 6 <= techlevel)
{
police_ship = [UNIVERSE newShipWithRole:@"interceptor"]; // retain count = 1
}
else
{
police_ship = [UNIVERSE newShipWithRole:@"police"]; // retain count = 1
}
if (police_ship)
{
if (![police_ship crew])
{
[police_ship setCrew:[NSArray arrayWithObject:
[OOCharacter randomCharacterWithRole: @"police"
andOriginalSystem: [UNIVERSE systemSeed]]]];
andOriginalSystem: [UNIVERSE systemSeed]]]];
}
[police_ship setPrimaryRole:@"police"];
[police_ship addTarget:[UNIVERSE entityForUniversalID:police_target]];
[police_ship setScanClass: CLASS_POLICE];
@ -1376,7 +1395,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
if (![UNIVERSE entityForUniversalID:defense_target])
{
[shipAI reactToMessage:@"TARGET_LOST"];
[self noteLostTarget];
return;
}
@ -1491,13 +1510,14 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
- (void) launchPirateShip
{
//Pirate ships are launched from the same pool as defence ships.
int defense_target = primaryTarget;
ShipEntity *pirate_ship;
if (police_launched >= max_defense_ships) // shuttles are to rockhermits what police ships are to stations
return;
OOUniversalID defense_target = primaryTarget;
ShipEntity *pirate_ship = nil;
if (police_launched >= max_defense_ships) return; // shuttles are to rockhermits what police ships are to stations
if (![UNIVERSE entityForUniversalID:defense_target])
{
[shipAI reactToMessage:@"TARGET_LOST"];
[self noteLostTarget];
return;
}
@ -1510,9 +1530,11 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
if (pirate_ship)
{
if (![pirate_ship crew])
{
[pirate_ship setCrew:[NSArray arrayWithObject:
[OOCharacter randomCharacterWithRole: @"pirate"
andOriginalSystem: [UNIVERSE systemSeed]]]];
andOriginalSystem: [UNIVERSE systemSeed]]]];
}
// set the owner of the ship to the station so that it can check back for docking later
[pirate_ship setOwner:self];
@ -1807,7 +1829,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
[super dumpSelfState];
switch (alert_level)
switch (alertLevel)
{
case STATION_ALERT_LEVEL_GREEN:
alertString = @"green";

View File

@ -145,8 +145,7 @@ static void DrawWormholeCorona(GLfloat inner_radius, GLfloat outer_radius, int s
[UNIVERSE addEntity:ship];
// Should probably pass the wormhole, but they have no JS representation
[ship doScriptEvent:@"shipExitedWormhole"];
[[ship getAI] reactToMessage:@"EXITED WITCHSPACE"];
[ship doScriptEvent:@"shipExitedWormhole" andReactToAIMessage:@"EXITED WITCHSPACE"];
// update the ships's position
[ship update: time_passed];

View File

@ -59,7 +59,7 @@ Vector OORandomUnitVector(void)
v = make_vector(randf() - 0.5f, randf() - 0.5f, randf() - 0.5f);
m = magnitude2(v);
}
while (m == 0.0f || m > 0.25f); // We're confining to a sphere of radius 0.5 using the sqared magnitude; 0.5 squared is 0.25.
while (m > 0.25f || m == 0.0f); // We're confining to a sphere of radius 0.5 using the sqared magnitude; 0.5 squared is 0.25.
return vector_normal(v);
}

View File

@ -303,7 +303,7 @@ static JSBool PlayerSetProperty(JSContext *context, JSObject *this, jsval name,
case kPlayer_score:
if (JS_ValueToInt32(context, *value, &iValue))
{
iValue = (int)OOMax_f(iValue, 0);
iValue = MAX(iValue, 0);
[player setScore:iValue];
}
break;

View File

@ -115,7 +115,8 @@ enum
kShip_isThargoid, // is thargoid, boolean, read-only
kShip_isTrader, // is trader, boolean, read-only
kShip_isPirateVictim, // is pirate victim, boolean, read-only
kShip_scriptInfo // arbitrary data for scripts, dictionary, read-only
kShip_scriptInfo, // arbitrary data for scripts, dictionary, read-only
kShip_trackCloseContacts // generate close contact events, boolean, read/write
};
@ -161,6 +162,7 @@ static JSPropertySpec sShipProperties[] =
{ "temperature", kShip_temperature, JSPROP_PERMANENT | JSPROP_ENUMERATE },
{ "weaponRange", kShip_weaponRange, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "withinStationAegis", kShip_withinStationAegis, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "trackCloseContacts", kShip_trackCloseContacts, JSPROP_PERMANENT | JSPROP_ENUMERATE },
{ 0 }
};
@ -390,6 +392,10 @@ static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsval name, js
result = [entity scriptInfo];
if (result == nil) result = [NSDictionary dictionary]; // empty rather than NULL
break;
case kShip_trackCloseContacts:
*outValue = BOOLToJSVal([entity trackCloseContacts]);
break;
default:
OOReportJavaScriptBadPropertySelector(context, @"Ship", JSVAL_TO_INT(name));
@ -516,6 +522,13 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js
[entity setReportAIMessages:bValue];
}
break;
case kShip_trackCloseContacts:
if (JS_ValueToBoolean(context, *value, &bValue))
{
[entity setTrackCloseContacts:bValue];
}
break;
default:
OOReportJavaScriptBadPropertySelector(context, @"Ship", JSVAL_TO_INT(name));
@ -644,7 +657,7 @@ static JSBool ShipReactToAIMessage(JSContext *context, JSObject *this, uintN arg
{
if (!thisEnt->isPlayer)
{
[[thisEnt getAI] reactToMessage:message];
[thisEnt reactToAIMessage:message];
}
else
{

View File

@ -65,7 +65,8 @@ enum
{
// Property IDs
kStation_isMainStation, // Is [UNIVERSE station], boolean, read-only
kStation_hasNPCTraffic
kStation_hasNPCTraffic,
kStation_alertCondition,
};
@ -74,6 +75,7 @@ static JSPropertySpec sStationProperties[] =
// JS name ID flags
{ "isMainStation", kStation_isMainStation, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "hasNPCTraffic", kStation_hasNPCTraffic, JSPROP_PERMANENT | JSPROP_ENUMERATE },
{ "alertCondition", kStation_alertCondition, JSPROP_PERMANENT | JSPROP_ENUMERATE },
{ 0 }
};
@ -143,6 +145,10 @@ static JSBool StationGetProperty(JSContext *context, JSObject *this, jsval name,
*outValue = BOOLToJSVal([entity hasNPCTraffic]);
break;
case kStation_alertCondition:
*outValue = INT_TO_JSVAL([entity alertLevel]);
break;
default:
OOReportJavaScriptBadPropertySelector(context, @"Station", JSVAL_TO_INT(name));
return NO;
@ -155,6 +161,8 @@ static JSBool StationSetProperty(JSContext *context, JSObject *this, jsval name,
{
StationEntity *entity = nil;
JSBool bValue;
int32 iValue;
if (!JSVAL_IS_INT(name)) return YES;
if (!JSStationGetStationEntity(context, this, &entity)) return NO;
@ -168,6 +176,13 @@ static JSBool StationSetProperty(JSContext *context, JSObject *this, jsval name,
}
break;
case kStation_alertCondition:
if (JS_ValueToInt32(context, *value, &iValue))
{
[entity setAlertLevel:iValue signallingScript:NO]; // Performs range checking
}
break;
default:
OOReportJavaScriptBadPropertySelector(context, @"Station", JSVAL_TO_INT(name));
return NO;

View File

@ -4635,6 +4635,15 @@ static BOOL MaintainLinkedLists(Universe* uni)
}
OOINLINE BOOL EntityInRange(Vector p1, Entity *e2, float range)
{
if (range < 0) return YES;
Vector p2 = vector_subtract(e2->position, p1);
float cr = range + e2->collision_radius;
return magnitude2(p2) < cr * cr;
}
// NOTE: OOJSSystem relies on this returning entities in distance-from-player order.
// This can be easily changed by removing the [reference isPlayer] conditions in FindJSVisibleEntities().
- (NSMutableArray *) findEntitiesMatchingPredicate:(EntityFilterPredicate)predicate
@ -4643,8 +4652,7 @@ static BOOL MaintainLinkedLists(Universe* uni)
ofEntity:(Entity *)e1
{
unsigned i;
Vector p1, p2;
double distance, cr;
Vector p1;
NSMutableArray *result = nil;
if (predicate == NULL) predicate = YESPredicate;
@ -4657,19 +4665,12 @@ static BOOL MaintainLinkedLists(Universe* uni)
for (i = 0; i < n_entities; i++)
{
Entity *e2 = sortedEntities[i];
if (e2 != e1 && predicate(e2, parameter))
if (e1 != e2 &&
EntityInRange(p1, e2, range) &&
predicate(e2, parameter))
{
if (range < 0) distance = -1; // Negative range means infinity
else
{
p2 = vector_subtract(e2->position, p1);
cr = range + e2->collision_radius;
distance = magnitude2(p2) - cr * cr;
}
if (distance < 0)
{
[result addObject:e2];
}
[result addObject:e2];
}
}

View File

@ -0,0 +1,116 @@
// Code to generate http://wiki.alioth.net/index.php/Image:Randomvectordistribution.png
#import <math.h>
#import <stdio.h>
static inline float randf(void)
{
return ((float)random()) / ((float)0x7FFFFFFF);
}
static inline float randcoord(void)
{
return (randf() * 2.0f) - 1.0f;
}
typedef struct
{
float x, y;
} Vector;
static Vector randv(void)
{
Vector r = { randcoord(), randcoord() };
return r;
}
static float magnitude2(Vector v)
{
return v.x * v.x + v.y * v.y;
}
static Vector scalev(Vector v, float s)
{
v.x *= s;
v.y *= s;
return v;
}
static Vector normal(Vector v)
{
float m = magnitude2(v);
return scalev(v, 1.0f / sqrtf(m));
}
static Vector uniformrandomv(void)
{
Vector v;
float m;
do
{
v = randv();
m = magnitude2(v);
}
while (m > 1.0f);
return v;
}
static Vector radialrandomv(void)
{
Vector v;
float m;
do
{
v = randv();
m = magnitude2(v);
}
while (m > 1.0f || m == 0.0f);
return scalev(normal(v), randf());
}
#define SIZE 200
static inline unsigned scalecoord(float c)
{
return (c + 1.0) * ((float)SIZE) * 0.5;
}
int main (int argc, const char * argv[])
{
unsigned char img[SIZE * SIZE] = {0};
srandomdev();
unsigned i;
for (i = 0; i < 2500; ++i)
{
Vector v = uniformrandomv();
unsigned x = scalecoord(v.x);
unsigned y = scalecoord(v.y);
img[y * SIZE + x] = 0xFF;
}
FILE *f = fopen("/dump.raw", "w");
fwrite(img, SIZE, SIZE, f);
fclose(f);
return 0;
}