From d483a2a18b42ea49f6f775ebb8eff5a1e68302aa Mon Sep 17 00:00:00 2001 From: cim Date: Fri, 3 Apr 2015 14:42:47 +0100 Subject: [PATCH] More work on explosions and wreckage shipdata.plist gets show_damage property to control if sparks, etc. are shown default to no if energy recharge is zero, yes otherwise, to mimic existing behaviour. Set hermit explicitly. --- Resources/Config/explosions.plist | 77 ++++++++++++++- Resources/Config/shipdata.plist | 35 +++++-- src/Core/Entities/OOExplosionCloudEntity.m | 5 +- src/Core/Entities/ShipEntity.h | 4 + src/Core/Entities/ShipEntity.m | 105 +++++++++++++-------- src/Core/Universe.h | 2 + src/Core/Universe.m | 61 ++++++++++++ 7 files changed, 237 insertions(+), 52 deletions(-) diff --git a/Resources/Config/explosions.plist b/Resources/Config/explosions.plist index 463f191b..bd65f328 100644 --- a/Resources/Config/explosions.plist +++ b/Resources/Config/explosions.plist @@ -1,4 +1,5 @@ { + // main ship explosion "oolite-default-ship-explosion" = { "alpha" = 0.85; "color_order" = "rgb"; @@ -9,13 +10,24 @@ "texture" = "oolite-particle-cloud2.png"; }; + // slower clouds from fragment explosions + "oolite-wreckage-explosion" = { + "alpha" = 0.85; + "color_order" = "rgb"; + "count" = 10; + "duration" = 4.5; + "growth_rate" = 0.6; + "size" = 2.5; + "texture" = "oolite-particle-cloud2.png"; + }; "oolite-fragment-explosion" = { "alpha" = 0.25; "color_order" = "rgb"; "count" = 5; - "duration" = 1.2; - "growth_rate" = 14; + "duration" = 1.85; + "growth_rate" = 7; + "spread" = 0.3; "size" = 1.0; "texture" = "oolite-particle-fragments.png"; }; @@ -24,13 +36,68 @@ "alpha" = 0.25; "color_order" = "rgb"; "count" = 5; - "duration" = 1.2; - "growth_rate" = 14; + "duration" = 1.75; + "growth_rate" = 5; "size" = 1.0; "texture" = "oolite-particle-fragments2.png"; }; - + + // spark effects as ships badly hit + "oolite-wreckage-chunk" = { + "alpha" = 0.85; + "color_order" = "rgb"; + "count" = 10; + "duration" = 1.2; + "growth_rate" = 2.6; + "size" = 2.5; + "texture" = "oolite-particle-cloud2.png"; + }; + + "oolite-wreckage-chunk-fragment" = { + "alpha" = 0.25; + "color_order" = "rgb"; + "count" = 5; + "duration" = 0.3; + "growth_rate" = 18; + "spread" = 0.3; + "size" = 1.0; + "texture" = "oolite-particle-fragments.png"; + }; + + "oolite-wreckage-chunk-fragment-b" = { + "alpha" = 0.25; + "color_order" = "rgb"; + "count" = 5; + "duration" = 0.4; + "growth_rate" = 12; + "size" = 1.0; + "texture" = "oolite-particle-fragments2.png"; + }; + + "oolite-hull-spark" = { + "alpha" = 0.65; + "color_order" = "bgr"; + "count" = 5; + "duration" = 0.22; + "growth_rate" = 3; + "spread" = 0.5; + "size" = 0.12; + "texture" = "oolite-particle-fragments.png"; + }; + + "oolite-hull-spark-b" = { + "alpha" = 0.85; + "color_order" = "white"; + "count" = 5; + "duration" = 0.25; + "growth_rate" = 3; + "spread" = 0.5; + "size" = 0.15; + "texture" = "oolite-particle-fragments2.png"; + }; + + // explosion for rocky bodies "oolite-default-asteroid-explosion" = { "alpha" = 0.85; "color_order" = "white"; diff --git a/Resources/Config/shipdata.plist b/Resources/Config/shipdata.plist index 8a3f9a6e..1431ee05 100644 --- a/Resources/Config/shipdata.plist +++ b/Resources/Config/shipdata.plist @@ -3108,6 +3108,7 @@ rotating = yes; requires_docking_clearance = no; scan_class = "CLASS_ROCK"; + show_damage = no; smooth = yes; station_roll = "0.06"; // 0.5G at rim subentities = @@ -3957,13 +3958,13 @@ ai_type = "nullAI.plist"; cargo_type = "CARGO_NOT_CARGO"; energy_recharge_rate = 0; - explosion_type = ("oolite-default-ship-explosion","oolite-fragment-explosion"); // no flash + explosion_type = ("oolite-wreckage-explosion","oolite-fragment-explosion"); // no flash forward_weapon_type = "WEAPON_NONE"; fragment_chance = 0.0; is_template = 1; - max_energy = 2000; - max_flight_pitch = 2; - max_flight_roll = 2; + max_energy = 20000; + max_flight_pitch = 0.2; + max_flight_roll = 0.2; max_flight_speed = 500; model = "wreck1.dat"; name = "Wreckage"; @@ -3973,6 +3974,13 @@ counts_as_kill = false; }; + "oolite_template_wreckage-chunk" = + { + like_ship = "oolite_template_wreckage-component"; + explosion_type = ("oolite-wreckage-chunk-explosion"); + roles = "oolite-wreckage-chunk"; + }; + /* Begin entity definitions. Graphics-modifying OXPs should * generally extend or copy these entries. OXPs should like_ship * these entries if they want their variant to look like @@ -4282,13 +4290,13 @@ "more-wreckage2" = { like_ship = "oolite_template_wreckage-component"; - explosion_type = ("oolite-default-ship-explosion","oolite-fragment-explosion-b"); + explosion_type = ("oolite-wreckage-explosion","oolite-fragment-explosion-b"); model = "wreck2.dat"; }; "more-wreckage3" = { like_ship = "oolite_template_wreckage-component"; - explosion_type = ("oolite-default-ship-explosion"); + explosion_type = ("oolite-wreckage-explosion"); model = "wreck3.dat"; }; "more-wreckage4" = @@ -4303,6 +4311,21 @@ explosion_type = ("oolite-fragment-explosion-b"); model = "wreck5.dat"; }; + "wreckage-chunk" = + { + like_ship = "oolite_template_wreckage-chunk"; + }; + "wreckage-chunk2" = + { + like_ship = "oolite_template_wreckage-chunk"; + explosion_type = ("oolite-wreckage-chunk-fragment"); + }; + "wreckage-chunk3" = + { + like_ship = "oolite_template_wreckage-chunk"; + explosion_type = ("oolite-wreckage-chunk-fragment-b"); + }; + /* Begin definitions for entities used in the tutorial */ diff --git a/src/Core/Entities/OOExplosionCloudEntity.m b/src/Core/Entities/OOExplosionCloudEntity.m index 131eed75..1867bc4c 100644 --- a/src/Core/Entities/OOExplosionCloudEntity.m +++ b/src/Core/Entities/OOExplosionCloudEntity.m @@ -43,6 +43,7 @@ static NSString * const kExplosionCount = @"count"; static NSString * const kExplosionDuration = @"duration"; static NSString * const kExplosionGrowth = @"growth_rate"; static NSString * const kExplosionSize = @"size"; +static NSString * const kExplosionSpread = @"spread"; static NSString * const kExplosionTexture = @"texture"; @@ -78,6 +79,8 @@ static NSString * const kExplosionTexture = @"texture"; _alpha = [_settings oo_floatForKey:kExplosionAlpha defaultValue:kExplosionCloudAlpha]; _cloudDuration = [_settings oo_floatForKey:kExplosionDuration defaultValue:kExplosionCloudDuration]; + GLfloat spread = [_settings oo_floatForKey:kExplosionSpread defaultValue:1.0]; + NSString *textureFile = [_settings oo_stringForKey:kExplosionTexture defaultValue:@"oolite-particle-cloud2.png"]; _texture = [[OOTexture textureWithName:textureFile @@ -99,7 +102,7 @@ static NSString * const kExplosionTexture = @"texture"; vel = vector_multiply_scalar(vector_normal(vel),1000); } - if ((self = [super initWithPosition:pos velocity:vel count:count minSpeed:size*0.8 maxSpeed:size*1.2 duration:_cloudDuration baseColor:baseColor])) + if ((self = [super initWithPosition:pos velocity:vel count:count minSpeed:size*0.8*spread maxSpeed:size*1.2*spread duration:_cloudDuration baseColor:baseColor])) { NSString *color_order = [_settings oo_stringForKey:kExplosionColors defaultValue:@"rgb"]; diff --git a/src/Core/Entities/ShipEntity.h b/src/Core/Entities/ShipEntity.h index 9878d925..6a8dff4e 100644 --- a/src/Core/Entities/ShipEntity.h +++ b/src/Core/Entities/ShipEntity.h @@ -265,6 +265,8 @@ typedef enum cloakPassive: 1, // cloak deactivates when main weapons or missiles are fired cloakAutomatic: 1, // cloak activates itself automatic during attack canFragment: 1, // Can it break into wreckage? + isWreckage: 1, // Is it wreckage? + _showDamage: 1, // Show damage? suppressExplosion: 1, // Avoid exploding on death (script hook) suppressAegisMessages: 1, // No script/AI messages sent by -checkForAegis, isMissile: 1, // Whether this was launched by fireMissile (used to track submunitions). @@ -976,6 +978,8 @@ typedef enum - (void) becomeLargeExplosion:(double) factor; - (void) becomeEnergyBlast; - (void) broadcastEnergyBlastImminent; +- (void) setIsWreckage:(BOOL)isw; +- (BOOL) showDamage; - (Vector) positionOffsetForAlignment:(NSString*) align; Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q, NSString* align); diff --git a/src/Core/Entities/ShipEntity.m b/src/Core/Entities/ShipEntity.m index b912c7c9..bf5b23c0 100644 --- a/src/Core/Entities/ShipEntity.m +++ b/src/Core/Entities/ShipEntity.m @@ -298,6 +298,7 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other); maxEnergy = [shipDict oo_floatForKey:@"max_energy" defaultValue:200.0f]; energy_recharge_rate = [shipDict oo_floatForKey:@"energy_recharge_rate" defaultValue:1.0f]; + _showDamage = [shipDict oo_boolForKey:@"show_damage" defaultValue:(energy_recharge_rate > 0)]; // Each new ship should start in seemingly good operating condition, unless specifically told not to - this does not affect the ship's energy levels [self setThrowSparks:[shipDict oo_boolForKey:@"throw_sparks" defaultValue:NO]]; @@ -359,6 +360,8 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other); // can it be 'mined' for alloys? canFragment = [shipDict oo_fuzzyBooleanForKey:@"fragment_chance" defaultValue:0.9]; + isWreckage = NO; + // can subentities be destroyed separately? isFrangible = [shipDict oo_boolForKey:@"frangible" defaultValue:YES]; @@ -2007,6 +2010,12 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other); { return NO; } + + if (isWreckage) + { + // wreckage won't collide + return NO; + } if (isMissile && [self shotTime] < 0.25) // not yet fused { @@ -2430,7 +2439,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other) [self takeHeatDamage: delta_t * ship_temperature]; // are we burning due to low energy - if ((energy < maxEnergy * 0.20)&&(energy_recharge_rate > 0.0)) // prevents asteroid etc. from burning + if ((energy < maxEnergy * 0.20)&&_showDamage) // prevents asteroid etc. from burning throw_sparks = YES; // burning effects @@ -8796,9 +8805,9 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context) double ecr = [e2 collisionRadius]; double d2 = magnitude2(p2) - ecr * ecr; // limit momentum transfer to relatively sensible levels - if (d2 < 1.0) + if (d2 < 0.1) { - d2 = 1.0; + d2 = 0.1; } double moment = amount*desired_range/d2; [e2 addImpactMoment:vector_normal(p2) fraction:moment]; @@ -8893,9 +8902,26 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context) - (void) rescaleBy:(GLfloat)factor { - // rescale mesh (and collision detection stuff) - [self setMesh:[[self mesh] meshRescaledBy:factor]]; - + _scaleFactor *= factor; + OOMesh *mesh = nil; + + NSDictionary *shipDict = [self shipInfoDictionary]; + NSString *modelName = [shipDict oo_stringForKey:@"model"]; + if (modelName != nil) + { + mesh = [OOMesh meshWithName:modelName + cacheKey:[NSString stringWithFormat:@"%@-%.3f",_shipKey,_scaleFactor] + materialDictionary:[shipDict oo_dictionaryForKey:@"materials"] + shadersDictionary:[shipDict oo_dictionaryForKey:@"shaders"] + smooth:[shipDict oo_boolForKey:@"smooth" defaultValue:NO] + shaderMacros:OODefaultShipShaderMacros() + shaderBindingTarget:self + scaleFactor:factor]; + + if (mesh == nil) return; + [self setMesh:mesh]; + } + // rescale subentities Entity *se = nil; foreach (se, [self subEntities]) @@ -8981,6 +9007,19 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context) } + +- (void) setIsWreckage:(BOOL)isw +{ + isWreckage = isw; +} + + +- (BOOL) showDamage +{ + return _showDamage; +} + + - (void) becomeExplosion { @@ -9010,6 +9049,7 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context) int speed_low = 200; GLfloat n_alloys = sqrtf(sqrtf(mass / 6000.0f)); NSUInteger numAlloys = 0; + BOOL canReleaseSubWreckage = isWreckage && ([UNIVERSE detailLevel] >= DETAIL_LEVEL_EXTRAS); if ([self status] == STATUS_DEAD) { @@ -9024,7 +9064,7 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context) if (!suppressExplosion) { - if (mass > 500000.0f && randf() < 0.25f) // big! + if (!isWreckage && mass > 500000.0f && randf() < 0.25f) // big! { // draw an expanding ring OORingEffectEntity *ring = [OORingEffectEntity ringFromEntity:self]; @@ -9164,7 +9204,7 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context) // throw out burning chunks of wreckage // - if (n_alloys && canFragment) + if ((n_alloys && canFragment) || canReleaseSubWreckage) { NSUInteger n_wreckage = 0; @@ -9173,42 +9213,27 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context) // Create wreckage only when UNIVERSE is less than half full. // (condition set in r906 - was < 0.75 before) --Kaks 2011.10.17 NSUInteger maxWrecks = 3; - // if it can cope with extra detail, allow more wreckage - if ([UNIVERSE detailLevel] >= DETAIL_LEVEL_EXTRAS) + if (n_alloys == 0) { - maxWrecks = 8; + // must be sub-wreckage here + n_wreckage = (mass > 600.0 && randf() < 0.2)?2:0; + } + else + { + n_wreckage = (n_alloys < maxWrecks)? floorf(randf()*(n_alloys+2)) : maxWrecks; } - n_wreckage = (n_alloys < maxWrecks)? floorf(n_alloys) : maxWrecks; } for (i = 0; i < n_wreckage; i++) { - ShipEntity* wreck = [UNIVERSE newShipWithRole:@"wreckage"]; // retain count = 1 - if (wreck) - { - GLfloat expected_mass = 0.1f * mass * (0.75 + 0.5 * randf()); - GLfloat wreck_mass = [wreck mass]; - GLfloat scale_factor = powf(expected_mass / wreck_mass, 0.33333333f); // cube root of volume ratio - [wreck rescaleBy: scale_factor]; - - Vector r1 = [octree randomPoint]; - HPVector rpos = HPvector_add(vectorToHPVector(quaternion_rotate_vector([self normalOrientation], r1)), xposition); - [wreck setPosition:rpos]; - - [wreck setVelocity:[self velocity]]; + Vector r1 = [octree randomPoint]; + Vector dir = quaternion_rotate_vector([self normalOrientation], r1); + HPVector rpos = HPvector_add(vectorToHPVector(dir), xposition); + GLfloat lifetime = 750.0 * randf() + 250.0 * i + 100.0; + ShipEntity *wreck = [UNIVERSE addWreckageFrom:self withRole:@"wreckage" at:rpos scale:1.0 lifetime:lifetime/2]; + + [wreck setVelocity:vector_add([wreck velocity],vector_multiply_scalar(vector_normal(dir),randf()*[wreck collisionRadius]))]; - quaternion_set_random(&q); - [wreck setOrientation:q]; - - [wreck setTemperature: 1000.0]; // take 1000e heat damage per second - [wreck setHeatInsulation: 1.0e7]; // very large! so it won't cool down - [wreck setEnergy: 750.0 * randf() + 250.0 * i + 100.0]; // burn for 0.25s -> 1.25s - - [UNIVERSE addEntity:wreck]; // STATUS_IN_FLIGHT, AI state GLOBAL - [wreck performTumble]; - [wreck rescaleBy: 1.0/scale_factor]; - [wreck release]; - } } n_alloys = randf() * n_alloys; } @@ -11575,7 +11600,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q [shot setRange:hitAtRange]; Vector vd = vector_forward_from_quaternion([shot orientation]); HPVector flash_pos = HPvector_add([shot position], vectorToHPVector(vector_multiply_scalar(vd, hitAtRange))); - [UNIVERSE addEntity:[OOFlashEffectEntity laserFlashWithPosition:flash_pos velocity:[victim velocity] color:laser_color]]; + [UNIVERSE addLaserHitEffectsAt:flash_pos against:victim damage:weapon_damage color:laser_color]; } } else @@ -11700,7 +11725,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q [shot setRange:hit_at_range]; Vector vd = vector_forward_from_quaternion([shot orientation]); HPVector flash_pos = HPvector_add([shot position], vectorToHPVector(vector_multiply_scalar(vd, hit_at_range))); - [UNIVERSE addEntity:[OOFlashEffectEntity laserFlashWithPosition:flash_pos velocity:[victim velocity] color:laser_color]]; + [UNIVERSE addLaserHitEffectsAt:flash_pos against:victim damage:weapon_damage color:laser_color]; } } @@ -11787,7 +11812,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q [shot setRange:hit_at_range]; Vector vd = vector_forward_from_quaternion([shot orientation]); HPVector flash_pos = HPvector_add([shot position], vectorToHPVector(vector_multiply_scalar(vd, hit_at_range))); - [UNIVERSE addEntity:[OOFlashEffectEntity laserFlashWithPosition:flash_pos velocity:[victim velocity] color:laser_color]]; + [UNIVERSE addLaserHitEffectsAt:flash_pos against:victim damage:weapon_damage color:laser_color]; } } else diff --git a/src/Core/Universe.h b/src/Core/Universe.h index 3cde5a21..636ab381 100644 --- a/src/Core/Universe.h +++ b/src/Core/Universe.h @@ -524,6 +524,8 @@ enum - (Entity*) hazardOnRouteFromEntity:(Entity *) e1 toDistance:(double)dist fromPoint:(HPVector) p2; - (HPVector) getSafeVectorFromEntity:(Entity *) e1 toDistance:(double)dist fromPoint:(HPVector) p2; +- (ShipEntity *) addWreckageFrom:(ShipEntity *)ship withRole:(NSString *)wreckRole at:(HPVector)rpos scale:(GLfloat)scale lifetime:(GLfloat)lifetime; +- (void) addLaserHitEffectsAt:(HPVector)pos against:(ShipEntity *)target damage:(float)damage color:(OOColor *)color; - (ShipEntity *) firstShipHitByLaserFromShip:(ShipEntity *)srcEntity inDirection:(OOWeaponFacing)direction offset:(Vector)offset gettingRangeFound:(GLfloat*)range_ptr; - (Entity *) firstEntityTargetedByPlayer; - (Entity *) firstEntityTargetedByPlayerPrecisely; diff --git a/src/Core/Universe.m b/src/Core/Universe.m index 27a3cabf..a4533ff2 100644 --- a/src/Core/Universe.m +++ b/src/Core/Universe.m @@ -5473,6 +5473,67 @@ static BOOL MaintainLinkedLists(Universe *uni) } +- (ShipEntity*) addWreckageFrom:(ShipEntity *)ship withRole:(NSString *)wreckRole at:(HPVector)rpos scale:(GLfloat)scale lifetime:(GLfloat)lifetime +{ + ShipEntity* wreck = [UNIVERSE newShipWithRole:wreckRole]; // retain count = 1 + Quaternion q; + if (wreck) + { + GLfloat expected_mass = 0.1f * [ship mass] * (0.75 + 0.5 * randf()); + GLfloat wreck_mass = [wreck mass]; + GLfloat scale_factor = powf(expected_mass / wreck_mass, 0.33333333f) * scale; // cube root of volume ratio + [wreck rescaleBy: scale_factor]; + + [wreck setPosition:rpos]; + + [wreck setVelocity:[ship velocity]]; + + quaternion_set_random(&q); + [wreck setOrientation:q]; + + [wreck setTemperature: 1000.0]; // take 1000e heat damage per second + [wreck setHeatInsulation: 1.0e7]; // very large! so it won't cool down + [wreck setEnergy: lifetime]; + + [wreck setIsWreckage:YES]; + + [UNIVERSE addEntity:wreck]; // STATUS_IN_FLIGHT, AI state GLOBAL + [wreck performTumble]; + // [wreck rescaleBy: 1.0/scale_factor]; + [wreck release]; + } + return wreck; +} + + + +- (void) addLaserHitEffectsAt:(HPVector)pos against:(ShipEntity *)target damage:(float)damage color:(OOColor *)color +{ + // low energy, start getting small surface explosions + if ([target showDamage] && [target energy] < [target maxEnergy]/2) + { + NSString *key = (randf() < 0.5) ? @"oolite-hull-spark" : @"oolite-hull-spark-b"; + NSDictionary *settings = [UNIVERSE explosionSetting:key]; + OOExplosionCloudEntity* burst = [OOExplosionCloudEntity explosionCloudFromEntity:target withSettings:settings]; + [burst setPosition:pos]; + [self addEntity: burst]; + if ([target energy] * randf() < damage) + { + ShipEntity *wreck = [self addWreckageFrom:target withRole:@"oolite-wreckage-chunk" at:pos scale:0.05 lifetime:(125.0+(randf()*200.0))]; + if (wreck) + { + Vector direction = HPVectorToVector(HPvector_normal(HPvector_subtract(pos,[target position]))); + [wreck setVelocity:vector_add([wreck velocity],vector_multiply_scalar(direction,10+20*randf()))]; + } + } + } + else + { + [self addEntity:[OOFlashEffectEntity laserFlashWithPosition:pos velocity:[target velocity] color:color]]; + } +} + + - (ShipEntity *) firstShipHitByLaserFromShip:(ShipEntity *)srcEntity inDirection:(OOWeaponFacing)direction offset:(Vector)offset gettingRangeFound:(GLfloat *)range_ptr { if (srcEntity == nil) return nil;