explosiongenerator.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 747 行 · 第 1/2 页
CPP
747 行
#include "StdAfx.h"
#include <fstream>
#include <stdexcept>
#include <SDL_types.h>
#include "creg/VarTypes.h"
#include "ExplosionGenerator.h"
#include "FileSystem/FileHandler.h"
#include "Game/Camera.h"
#include "LogOutput.h"
#include "Map/Ground.h"
#include "Platform/ConfigHandler.h"
#include "Rendering/GL/myGL.h"
#include "Rendering/GroundFlash.h"
#include "Rendering/Textures/ColorMap.h"
#include "Sim/Projectiles/ProjectileHandler.h"
#include "Sim/Projectiles/Unsynced/BubbleProjectile.h"
#include "Sim/Projectiles/Unsynced/DirtProjectile.h"
#include "Sim/Projectiles/Unsynced/ExploSpikeProjectile.h"
#include "Sim/Projectiles/Unsynced/HeatCloudProjectile.h"
#include "Sim/Projectiles/Unsynced/SmokeProjectile2.h"
#include "Sim/Projectiles/Unsynced/SpherePartProjectile.h"
#include "Sim/Projectiles/Unsynced/WakeProjectile.h"
#include "Sim/Projectiles/Unsynced/WreckProjectile.h"
#include "mmgr.h"
using namespace std;
CR_BIND_DERIVED_INTERFACE(CExpGenSpawnable, CWorldObject);
CR_REG_METADATA(CExpGenSpawnable,
);
CExplosionGeneratorHandler* explGenHandler = NULL;
// -------------------------------------------------------------------------------
// ClassAliasList: Finds C++ classes with class aliases
// -------------------------------------------------------------------------------
ClassAliasList::ClassAliasList() {}
void ClassAliasList::Load(const LuaTable& aliasTable)
{
map<string, string> aliasList;
aliasTable.GetMap(aliasList);
aliases.insert(aliasList.begin(), aliasList.end());
}
creg::Class* ClassAliasList::GetClass(const string& name)
{
string n = name;
for (;;) {
map<string,string>::iterator i = aliases.find(n);
if (i == aliases.end())
break;
n = i->second;
}
creg::Class *cls = creg::System::GetClass(n);
if (!cls)
throw content_error("Unknown class: " + name);
return cls;
}
string ClassAliasList::FindAlias(const string& className)
{
for (map<string,string>::iterator i = aliases.begin(); i != aliases.end(); ++i)
if (i->second == className) return i->first;
return className;
}
// -------------------------------------------------------------------------------
// Explosion generator handler: loads and stores a list of explosion generators
// -------------------------------------------------------------------------------
CExplosionGeneratorHandler::CExplosionGeneratorHandler()
: luaParser("gamedata/explosions.lua",
SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP)
{
LuaParser aliasParser("gamedata/explosion_alias.lua",
SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP);
if (!aliasParser.Execute()) {
logOutput.Print(aliasParser.GetErrorLog());
} else {
const LuaTable root = aliasParser.GetRoot();
projectileClasses.Load(root.SubTable("projectiles"));
generatorClasses.Load(root.SubTable("generators"));
}
if (!luaParser.Execute()) {
logOutput.Print(luaParser.GetErrorLog());
} else {
luaTable = luaParser.GetRoot();
}
}
CExplosionGenerator* CExplosionGeneratorHandler::LoadGenerator(const string& tag)
{
string klass;
string::size_type seppos = tag.find(':');
if (seppos == string::npos) {
klass = tag;
} else {
klass = tag.substr(0, seppos);
}
creg::Class *cls = generatorClasses.GetClass(klass);
if (!cls->IsSubclassOf(CExplosionGenerator::StaticClass())) {
throw content_error(klass + " is not a subclass of CExplosionGenerator");
}
CExplosionGenerator* eg = (CExplosionGenerator *)cls->CreateInstance();
if (seppos != string::npos) {
eg->Load(this, tag.substr(seppos + 1));
}
return eg;
}
// -------------------------------------------------------------------------------
// Base explosion generator class
// -------------------------------------------------------------------------------
CR_BIND_INTERFACE(CExplosionGenerator);
CExplosionGenerator::CExplosionGenerator()
{}
CExplosionGenerator::~CExplosionGenerator()
{}
// -------------------------------------------------------------------------------
// Default explosion generator: everything is calculated from damage and radius
// -------------------------------------------------------------------------------
CR_BIND_DERIVED(CStdExplosionGenerator, CExplosionGenerator, );
CStdExplosionGenerator::CStdExplosionGenerator()
{}
CStdExplosionGenerator::~CStdExplosionGenerator()
{}
void CStdExplosionGenerator::Load(CExplosionGeneratorHandler *h, const string& tag)
{
}
void CStdExplosionGenerator::Explosion(const float3 &pos, float damage, float radius, CUnit *owner,float gfxMod, CUnit *hit, const float3 &dir)
{
PUSH_CODE_MODE;
ENTER_MIXED;
float h2=ground->GetHeight2(pos.x,pos.z);
float height=pos.y-h2;
if (height < 0.0f) {
height = 0.0f;
}
bool waterExplosion = h2 < -3;
bool uwExplosion = pos.y < -15;
bool airExplosion = pos.y - max((float)0, h2) > 20;
damage=damage/20;
if (damage>radius*1.5f) //limit the visual effects based on the radius
damage=radius*1.5f;
damage*=gfxMod;
for (int a=0;a<1;++a) {
// float3 speed((gs->randFloat()-0.5f)*(radius*0.04f),0.05f+(gs->randFloat())*(radius*0.007f),(gs->randFloat()-0.5f)*(radius*0.04f));
float3 speed(0,0.3f,0);
float3 camVect=camera->pos-pos;
float camLength=camVect.Length();
camVect/=camLength;
float moveLength=radius*0.03f;
if (camLength<moveLength+2)
moveLength=camLength-2;
float3 npos=pos+camVect*moveLength;
SAFE_NEW CHeatCloudProjectile(npos,speed,8+sqrt(damage)*0.5f,7+damage*2.8f,owner);
}
if (ph->particleSaturation<1) { //turn off lots of graphic only particles when we have more particles than we want
float smokeDamage=damage;
if (uwExplosion)
smokeDamage*=0.3f;
if (airExplosion || waterExplosion)
smokeDamage*=0.6f;
float invSqrtsmokeDamage=1/(sqrt(smokeDamage)*0.35f);
for (int a=0;a<smokeDamage*0.6f;++a) {
float3 speed(-0.1f+gu->usRandFloat()*0.2f,(0.1f+gu->usRandFloat()*0.3f)*invSqrtsmokeDamage,-0.1f+gu->usRandFloat()*0.2f);
float3 npos(pos+gu->usRandVector()*(smokeDamage*1.0f));
float h=ground->GetApproximateHeight(npos.x,npos.z);
if (npos.y<h)
npos.y=h;
float time=(40+sqrt(smokeDamage)*15)*(0.8f+gu->usRandFloat()*0.7f);
SAFE_NEW CSmokeProjectile2(pos,npos,speed,time,sqrt(smokeDamage)*4,0.4f,owner,0.6f);
}
if (!airExplosion && !uwExplosion && !waterExplosion) {
int numDirt=(int)min(20.f,damage*0.8f);
float3 color(0.15f,0.1f,0.05f);
for (int a=0;a<numDirt;++a) {
float3 speed((0.5f-gu->usRandFloat())*1.5f,1.7f+gu->usRandFloat()*1.6f,(0.5f-gu->usRandFloat())*1.5f);
speed*=0.7f+min((float)30,damage)/30;
float3 npos(pos.x-(0.5f-gu->usRandFloat())*(radius*0.6f),pos.y-2.0f-damage*0.2f,pos.z-(0.5f-gu->usRandFloat())*(radius*0.6f));
SAFE_NEW CDirtProjectile(npos,speed,90+damage*2,2.0f+sqrt(damage)*1.5f,0.4f,0.999f,owner,color);
}
}
if (!airExplosion && !uwExplosion && waterExplosion) {
int numDirt=(int)min(40.f,damage*0.8f);
float3 color(1,1,1);
for (int a=0;a<numDirt;++a) {
float3 speed((0.5f-gu->usRandFloat())*0.2f,a*0.1f+gu->usRandFloat()*0.8f,(0.5f-gu->usRandFloat())*0.2f);
speed*=0.7f+min((float)30,damage)/30;
float3 npos(pos.x-(0.5f-gu->usRandFloat())*(radius*0.2f),pos.y-2.0f-sqrt(damage)*2.0f,pos.z-(0.5f-gu->usRandFloat())*(radius*0.2f));
SAFE_NEW CDirtProjectile(npos,speed,90+damage*2,2.0f+sqrt(damage)*2.0f,0.3f,0.99f,owner,color);
}
}
if (damage>=20 && !uwExplosion && !airExplosion) {
int numDebris=gu->usRandInt()%6;
if (numDebris>0)
numDebris+=3+(int)(damage*0.04f);
for (int a=0;a<numDebris;++a) {
float3 speed;
if (height<4)
speed=float3((0.5f-gu->usRandFloat())*2.0f,1.8f+gu->usRandFloat()*1.8f,(0.5f-gu->usRandFloat())*2.0f);
else
speed=float3(gu->usRandVector()*2);
speed*=0.7f+min((float)30,damage)/23;
float3 npos(pos.x-(0.5f-gu->usRandFloat())*(radius*1),pos.y,pos.z-(0.5f-gu->usRandFloat())*(radius*1));
SAFE_NEW CWreckProjectile(npos,speed,90+damage*2,owner);
}
}
if (uwExplosion) {
int numBubbles=(int)(damage*0.7f);
for (int a=0;a<numBubbles;++a) {
SAFE_NEW CBubbleProjectile(pos+gu->usRandVector()*radius*0.5f,gu->usRandVector()*0.2f+float3(0,0.2f,0),damage*2+gu->usRandFloat()*damage,1+gu->usRandFloat()*2,0.02f,owner,0.5f+gu->usRandFloat()*0.3f);
}
}
if (waterExplosion && !uwExplosion && !airExplosion) {
int numWake=(int)(damage*0.5f);
for (int a=0;a<numWake;++a) {
SAFE_NEW CWakeProjectile(pos+gu->usRandVector()*radius*0.2f,gu->usRandVector()*radius*0.003f,sqrt(damage)*4,damage*0.03f,owner,0.3f+gu->usRandFloat()*0.2f,0.8f/(sqrt(damage)*3+50+gu->usRandFloat()*90),1);
}
}
if (radius>10 && damage>4) {
int numSpike=(int)sqrt(damage)+8;
for (int a=0;a<numSpike;++a) {
float3 speed=gu->usRandVector();
speed.Normalize();
speed*=(8+damage*3.0f)/(9+sqrt(damage)*0.7f)*0.35f;
if (!airExplosion && !waterExplosion && speed.y<0)
speed.y=-speed.y;
SAFE_NEW CExploSpikeProjectile(pos+speed,speed*(0.9f+gu->usRandFloat()*0.4f),radius*0.1f,radius*0.1f,0.6f,0.8f/(8+sqrt(damage)),owner);
}
}
}
if (radius > 20 && damage > 6 && height < radius * 0.7f) {
float modSize=max(radius,damage*2);
float circleAlpha=0;
float circleGrowth=0;
float ttl=8+sqrt(damage)*0.8f;
if (radius>40 && damage>12) {
circleAlpha=min(0.5f,damage*0.01f);
circleGrowth=(8+damage*2.5f)/(9+sqrt(damage)*0.7f)*0.55f;
}
float flashSize=modSize;
float flashAlpha=min(0.8f,damage*0.01f);
SAFE_NEW CStandardGroundFlash(pos,circleAlpha,flashAlpha,flashSize,circleGrowth,ttl);
}
if (radius > 40 && damage > 12) {
CSpherePartProjectile::CreateSphere(pos,min(0.7f,damage*0.02f),5+(int)(sqrt(damage)*0.7f),(8+damage*2.5f)/(9+sqrt(damage)*0.7f)*0.5f,owner);
}
POP_CODE_MODE;
}
// -------------------------------------------------------------------------------
// CCustomExplosionGenerator: Uses explosion info from a TDF file
// -------------------------------------------------------------------------------
CR_BIND_DERIVED(CCustomExplosionGenerator, CStdExplosionGenerator, );
#define SPW_WATER 1
#define SPW_GROUND 2
#define SPW_AIR 4
#define SPW_UNDERWATER 8
#define SPW_UNIT 16 // only execute when the explosion hits a unit
#define SPW_NO_UNIT 32 // only execute when the explosion doesn't hit a unit (environment)
CCustomExplosionGenerator::CCustomExplosionGenerator()
{
groundFlash = 0;
}
CCustomExplosionGenerator::~CCustomExplosionGenerator()
{
if (groundFlash)
delete groundFlash;
}
#define OP_END 0
#define OP_STOREI 1 // int
#define OP_STOREF 2 // float
#define OP_STOREC 3 // char
#define OP_ADD 4
#define OP_RAND 5
#define OP_DAMAGE 6
#define OP_INDEX 7
#define OP_LOADP 8 // load a void* into the pointer register
#define OP_STOREP 9 // store the pointer register into a void*
#define OP_DIR 10 // store the float3 direction
#define OP_SAWTOOTH 11 // Performs a modulo to create a sawtooth wave
#define OP_DISCRETE 12 // Floors the value to a multiple of its parameter
#define OP_SINE 13 // Uses val as the phase of a sine wave
#define OP_YANK 14 // Moves the input value into a buffer, returns zero
#define OP_MULTIPLY 15 // Multiplies with buffer value
#define OP_ADDBUFF 16 // Adds buffer value
#define OP_POW 17 // Power with code as exponent
#define OP_POWBUFF 18 // Power with buffer as exponent
void CCustomExplosionGenerator::ExecuteExplosionCode(const char *code, float damage, char *instance, int spawnIndex, const float3 &dir)
{
float val = 0.0f;
void* ptr = NULL;
float buffer[16];
for (;;) {
switch (*(code++)) {
case OP_END: {
return;
}
case OP_STOREI: {
Uint16 offset = *(Uint16*) code;
code += 2;
*(int*) (instance + offset) = (int) val;
val = 0.0f;
break;
}
case OP_STOREF: {
Uint16 offset = *(Uint16*) code;
code += 2;
*(float*) (instance + offset) = val;
val = 0.0f;
break;
}
case OP_STOREC: {
Uint16 offset = *(Uint16*) code;
code += 2;
*(unsigned char*) (instance + offset) = (int) val;
val = 0.0f;
break;
}
case OP_ADD: {
val += *(float*) code;
code += 4;
break;
}
case OP_RAND: {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?