added item spawning functionality and better effect for meteor; added alien meteor skin

squashed:
-Made meteor particle effect awesome
--Slight changes to rotation of Alien meteor and particles
-cleaned up alien meteor and merged item spawning functionality into normal meteor
-Fixed AlienMeteor spawn chance
-Changed AlienMeteor visuals slightly
-Made AlienMeteor Particles even better C:
-WIP: Alien meteor + particles
Controls
WinExploder 2015-08-29 19:53:52 +02:00 committed by David Dormagen
parent 38806f4c0b
commit 6257d9d6be
14 changed files with 319 additions and 40 deletions

View File

@ -163,4 +163,10 @@ private func Hatch()
PV_Random(10, 20), particles, 60);
RemoveObject();
return true;
}
}
// If spawned via a meteor, use a cool green skin.
public func GetMeteorSkin()
{
return Meteor_Alien;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,3 @@
[Particle]
Name=BlueFire
Face=0,0,64,64,-32,-32

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -0,0 +1,3 @@
[Particle]
Name=BlueFireTrail
Face=0,0,256,256,-128,-218

View File

@ -0,0 +1,14 @@
[DefCore]
id=Meteor_Alien
Version=6,0
Category=C4D_Object|C4D_Environment
Width=27
Height=41
Offset=-13,-20
Vertices=4
VertexX=-7,-7,7,7
VertexY=-7,7,-7,7
VertexFriction=50,50,50,50
Rotate=1
NoStabilize=1
StretchGrowth=1

View File

@ -0,0 +1,27 @@
material AlienMeteoriteMat: NormalMap
{
receive_shadows off
technique
{
pass
{
ambient 1.0 1.0 1.0 1.0
diffuse 1.0 1.0 1.0 1.0
specular 0.25 0.25 0.25 1.0 12.5
emissive 0.0 0.0 0.0 1.0
texture_unit base
{
texture meteorite.png
tex_address_mode wrap
filtering trilinear
}
texture_unit normal
{
texture meteorite_normals.png
tex_address_mode wrap
}
}
}
}

View File

@ -0,0 +1,109 @@
/**
Alien Meteor Skin
A new meteorite skin that can f.e. be used when spawning aliens.
@author Win
*/
#include Meteor
public func OnAfterLaunch()
{
// Adjust rotation to point into movement direction.
// You can't do this unless you also change the rotation of the trail -Win
//SetR(Angle(0, 0, GetXDir(), GetYDir()));
// Emits light
SetLightRange(400, 100);
SetLightColor(RGB(100, 254, 255));
// Add particle effects.
AddEffect("IntMeteor", this, 100, 1, this);
}
private func FxIntMeteorStart(object target, effect fx, bool temp)
{
if (temp) return;
fx.fire =
{
R = 255,
B = 255,
G = 255,
Alpha = PV_Linear(255,0),
Size = PV_Linear(30,150),
Stretch = 1000,
Phase = 0,
Rotation = PV_Random(-GetR() - 15, -GetR() + 15),
DampingX = 1000,
DampingY = 1000,
BlitMode = GFX_BLIT_Additive,
CollisionVertex = 0,
OnCollision = PC_Die(),
Attach = nil
};
fx.sparkright =
{
R = 255,
B = 255,
G = 255,
Alpha = PV_KeyFrames(0, 0, 0, 500, 255, 1000, 0),
Size = PV_Linear(20,100),
Stretch = 1000,
Phase = 0,
Rotation = 30,
ForceX = 0,
ForceY = 0,
DampingX = 1000,
DampingY = 1000,
BlitMode = GFX_BLIT_Additive,
CollisionVertex = 0,
OnCollision = PC_Die(),
Attach = ATTACH_Back | ATTACH_MoveRelative
};
fx.sparkleft =
{
Prototype = fx.sparkright,
Size = PV_Linear(30,100),
Rotation = -30,
};
fx.trail =
{
R = 255,
B = 255,
G = 255,
Alpha = PV_Linear(255,0),
Size = GetCon()/3,
Stretch = 1000,
Phase = 0,
Rotation = 0,
ForceX = 0,
ForceY = 0,
DampingX = 1000,
DampingY = 1000,
BlitMode = GFX_BLIT_Additive,
CollisionVertex = 0,
OnCollision = PC_Die(),
Attach = ATTACH_Front | ATTACH_MoveRelative
};
}
private func FxIntMeteorTimer(object target, effect fx)
{
var size = GetCon();
// Air drag.
var ydir = GetYDir(100);
ydir -= size * ydir ** 2 / 11552000; // Magic number.
SetYDir(ydir, 100);
// Fire trail.
fx.fire.ForceX = -GetXDir()/2 + RandomX(-5,5);
fx.fire.ForceY = -GetYDir()/2;
CreateParticle("BlueFireTrail", PV_Random(-1, 1), -15, 0, -GetYDir(), 7, fx.trail, 1);
CreateParticle("BlueSpark", 10, 15, 100 + GetXDir(), -GetYDir(), 20, fx.sparkright, 1);
CreateParticle("BlueSpark", -10, 15, -100 + GetXDir(), -GetYDir(), 20, fx.sparkleft, 1);
CreateParticle("BlueFire", PV_Random(-8, 8), PV_Random(-15, -35), 0, 0, 30, fx.fire, 4);
return 1;
}
/*-- Proplist --*/
local Name = "$Name$";

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -2,65 +2,102 @@
Meteor
A burning rock falling from the sky, explodes on impact.
@author Maikel
@author Maikel, Zapper
*/
// A meteor can spawn objects on impact.
local spawn_id, spawn_amount;
/*-- Disaster Control --*/
public func SetChance(int chance)
/**
Enables meteorites.
The meteorites can be set to spawn objects on impact. The amount to spawn will be spawn_amount randomized by 50%.
*/
public func SetChance(int chance, id spawn_id, int spawn_amount)
{
if (this != Meteor)
return;
var effect = GetEffect("IntMeteorControl");
spawn_amount = spawn_amount ?? 1;
if (GetType(this) != C4V_Def) return FatalError("Must be called as a definition call.");
var effect = FindMeteoriteEffectFor(spawn_id);
if (!effect)
effect = AddEffect("IntMeteorControl", nil, 100, 20, nil, Meteor);
effect = AddEffect("IntMeteorControl", nil, 100, 20, nil, this, spawn_id, spawn_amount);
effect.chance = chance;
return;
return true;
}
public func GetChance()
/**
Returns the chance of meteorites that is currently set. spawn_id can be nil for the normal meteorite.
*/
public func GetChance(id spawn_id)
{
if (this != Meteor)
return;
var effect = GetEffect("IntMeteorControl");
if (GetType(this) != C4V_Def) return FatalError("Must be called as a definition call.");
var effect = FindMeteoriteEffectFor(spawn_id);
if (effect)
return effect.chance;
return;
return 0;
}
protected func FxIntMeteorControlTimer(object target, proplist effect, int time)
// Finds the meteorite effect that matches a specific spawn id.
private func FindMeteoriteEffectFor(id spawn_id)
{
if (Random(100) < effect.chance && !Random(10))
var i = 0, fx;
while (fx = GetEffect("IntMeteorControl", nil, i++))
{
if (fx.spawn_id == spawn_id) return fx;
}
return nil;
}
private func FxIntMeteorControlStart(object target, effect fx, temp, id spawn_id, int spawn_amount)
{
if (temp) return;
fx.spawn_id = spawn_id;
fx.spawn_amount = spawn_amount;
}
private func FxIntMeteorControlTimer(object target, effect fx, int time)
{
if (Random(100) < fx.chance && !Random(10))
{
// Launch a meteor.
var meteor = CreateObjectAbove(Meteor);
var x = Random(LandscapeWidth());
var y = 0;
var size = RandomX(60, 90);
var xdir = RandomX(-22, 22);
var ydir = RandomX(28, 36);
meteor->Launch(x, y, size, xdir, ydir);
var real_spawn_amount = Max(1, RandomX(fx.spawn_amount / 2, 3 * fx.spawn_amount / 2));
LaunchMeteor(x, y, size, xdir, ydir, fx.spawn_id, real_spawn_amount);
}
return FX_OK;
}
// Scenario saving
func FxIntMeteorControlSaveScen(obj, fx, props)
public func FxIntMeteorControlSaveScen(obj, fx, props)
{
props->Add("Meteor", "Meteor->SetChance(%d)", fx.chance);
props->Add("Meteor", "Meteor->SetChance(%d, %v, %d)", fx.chance, fx.spawn_id, fx.spawn_amount);
return true;
}
global func LaunchMeteor(int x, int y, int size, int xdir, int ydir)
/**
Launches a meteor.
The meteor can spawn objects via spawn_id.
*/
global func LaunchMeteor(int x, int y, int size, int xdir, int ydir, id spawn_id, int spawn_amount)
{
var meteor = CreateObjectAbove(Meteor);
return meteor->Launch(x, y, size, xdir, ydir);
var meteor_skin = Meteor;
if (spawn_id) meteor_skin = spawn_id->~GetMeteorSkin() ?? meteor_skin;
var meteor = CreateObject(meteor_skin);
return meteor->Launch(x, y, size, xdir, ydir, spawn_id, spawn_amount);
}
/*-- Meteor --*/
public func Launch(int x, int y, int size, int xdir, int ydir)
public func Launch(int x, int y, int size, int xdir, int ydir, id spawn_id, int spawn_amount)
{
// Launch from indicated position.
SetPosition(x, y);
@ -69,15 +106,27 @@ public func Launch(int x, int y, int size, int xdir, int ydir)
// Set the initial velocity.
SetXDir(xdir);
SetYDir(ydir);
// Set random rotation.
SetR(Random(360));
SetRDir(RandomX(-10, 10));
// Remember spawning information.
this.spawn_id = spawn_id;
this.spawn_amount = spawn_amount ?? 1;
// Safety check.
if (!IsLaunchable())
return false;
// Allow for some more effects (overloadable).
this->OnAfterLaunch();
return true;
}
public func OnAfterLaunch()
{
// Set random rotation.
SetR(Random(360));
SetRDir(RandomX(-10, 10));
// Emit light
SetLightRange(300, 100);
SetLightColor(RGB(100, 230, 120));
// Set right action.
AddEffect("IntMeteor", this, 100, 1, this);
return true;
}
private func IsLaunchable()
@ -90,7 +139,55 @@ private func IsLaunchable()
return true;
}
protected func FxIntMeteorTimer()
private func FxIntMeteorStart(object target, effect fx, bool temp)
{
if (temp) return;
fx.smoketrail =
{
R = 255,
B = PV_KeyFrames(0, 0,100, 30,0, 100,255, 1000,255),
G = PV_KeyFrames(0, 0,150, 30,0, 100,255, 1000,255),
Alpha = PV_KeyFrames(1000, 0, 0, 30, 255, 1000, 0),
Size = PV_Linear(20,60),
Stretch = 1000,
Phase = PV_Random(0,4),
Rotation = PV_Random(-GetR() - 15, -GetR() + 15),
DampingX = 1000,
DampingY = 1000,
BlitMode = 0,
CollisionVertex = 0,
OnCollision = PC_Stop(),
Attach = nil
};
fx.brighttrail =
{
Prototype = fx.smoketrail,
Alpha = PV_Linear(180,0),
Size = PV_Linear(20,30),
BlitMode = GFX_BLIT_Additive,
};
fx.frontburn =
{
R = 255,
B = 50,
G = 190,
Alpha = PV_KeyFrames(0, 0, 0, 500, 25, 1000, 0),
Size = PV_Linear(4,5),
Stretch = 1000,
Phase = PV_Random(0,4),
Rotation = PV_Random(-GetR() - 15, -GetR() + 15),
DampingX = 1000,
DampingY = 1000,
BlitMode = GFX_BLIT_Additive,
CollisionVertex = 0,
OnCollision = PC_Stop(),
Attach = ATTACH_Front | ATTACH_MoveRelative
};
}
protected func FxIntMeteorTimer(object target, effect fx, bool temp)
{
var size = GetCon();
// Air drag.
@ -98,10 +195,12 @@ protected func FxIntMeteorTimer()
ydir -= size * ydir ** 2 / 11552000; // Magic number.
SetYDir(ydir, 100);
// Smoke trail.
CreateParticle("Smoke", PV_Random(-2, 2), PV_Random(-2, 2), PV_Random(-3, 3), PV_Random(-3, 3), 30 + Random(60), Particles_SmokeTrail(), 5);
// Fire trail.
CreateParticle("MagicSpark", 0, 0, PV_Random(-20, 20), PV_Random(-20, 20), 16, Particles_SparkFire(), 4);
CreateParticle("Fire", PV_Random(-size / 8, size / 8), PV_Random(-size / 8, size / 8), PV_Random(-1, 1), PV_Random(-1, 1), 30, Particles_FireTrail(), 6 + size / 10);
CreateParticle("SmokeThick", 0, 0, PV_Random(-3, 3), PV_Random(-3, 3), 200, fx.smoketrail, 5);
// Flash
CreateParticle("SmokeThick", 0, -4, PV_Random(-3, 3), PV_Random(-3, 3), 3, fx.brighttrail, 2);
// left and right burn
CreateParticle("FireDense", PV_Random(-5, 5), 15, PV_Random(-5, -20), PV_Random(-15, -30), 20, fx.frontburn, 30);
CreateParticle("FireDense", PV_Random(-5, 5), 15, PV_Random(5, 20), PV_Random(-15, -30), 20, fx.frontburn, 30);
// Sound.
// Burning and friction decrease size.
@ -111,6 +210,13 @@ protected func FxIntMeteorTimer()
return 1;
}
// Scenario saving
func FxIntMeteorSaveScen(obj, fx, props)
{
props->AddCall("Meteor", obj, "AddEffect", "\"IntMeteor\"", obj, 100, 1, obj);
return true;
}
protected func Hit(int xdir, int ydir)
{
var size = 10 + GetCon();
@ -125,17 +231,26 @@ protected func Hit(int xdir, int ydir)
// Explode meteor, explode size scales with the energy of the meteor.
var dam = size * speed2 / 500;
dam = BoundBy(size/2, 5, 30);
Explode(dam);
// Blow up a dummy object so that the explosion can happen before we spawn items.
var dummy = CreateObject(Dummy, 0, 0, GetController());
dummy->Explode(dam);
// Fling around some objects?
if (spawn_id)
{
for (var i = 0; i < spawn_amount; ++i)
{
var angle = Angle(0, 0, -xdir, -ydir) + RandomX(-45, 45);
var force = BoundBy(GetCon() / 2, 10, 50) + RandomX(-10, 10);
var item = CreateObject(spawn_id, 0, 0, GetOwner());
item->SetSpeed(Sin(angle, force), -Cos(angle, force));
}
}
RemoveObject();
return;
}
// Scenario saving
func FxIntMeteorSaveScen(obj, fx, props)
{
props->AddCall("Meteor", obj, "AddEffect", "\"IntMeteor\"", obj, 100, 1, obj);
return true;
}
/*-- Proplist --*/
local Name = "$Name$";