explosiongenerator.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 747 行 · 第 1/2 页
CPP
747 行
val += gu->usRandFloat() * (*(float*) code);
code += 4;
break;
}
case OP_DAMAGE: {
val += damage * (*(float*) code);
code += 4;
break;
}
case OP_INDEX: {
val += spawnIndex * (*(float*) code);
code += 4;
break;
}
case OP_LOADP: {
ptr = *(void**) code;
code += sizeof(void*);
break;
}
case OP_STOREP: {
Uint16 offset = *(Uint16*) code;
code += 2;
*(void**) (instance + offset) = ptr;
ptr = NULL;
break;
}
case OP_DIR: {
Uint16 offset = *(Uint16*) code;
code += 2;
*(float3*) (instance + offset) = dir;
break;
}
case OP_SAWTOOTH: {
// this translates to modulo except it works with floats
val -= (*(float*) code) * floor(val / (*(float*) code));
code += 4;
break;
}
case OP_DISCRETE: {
val = (*(float*) code) * floor(val / (*(float*) code));
code += 4;
break;
}
case OP_SINE: {
val = (*(float*) code) * sin(val);
code += 4;
break;
}
case OP_YANK: {
buffer[(*(int*) code)] = val;
val = 0;
code += 4;
break;
}
case OP_MULTIPLY: {
val *= buffer[(*(int*) code)];
code += 4;
break;
}
case OP_ADDBUFF: {
val += buffer[(*(int*) code)];
code += 4;
break;
}
case OP_POW: {
val = pow(val, (*(float*) code));
code += 4;
break;
}
case OP_POWBUFF: {
val = pow(val, buffer[(*(int*) code)]);
code += 4;
break;
}
default: {
assert(false);
break;
}
}
}
}
void CCustomExplosionGenerator::ParseExplosionCode(
CCustomExplosionGenerator::ProjectileSpawnInfo *psi,
int offset, creg::IType *type, const string& script, string& code)
{
string::size_type end = script.find(';', 0);
string vastr = script.substr(0, end);
if (vastr == "dir") {//first see if we can match any keywords
//if the user uses a keyword assume he knows that it is put on the right datatype for now
code += OP_DIR;
Uint16 ofs = offset;
code.append((char*) &ofs, (char*) &ofs + 2);
}
else if (dynamic_cast<creg::BasicType*>(type)) {
creg::BasicType *bt = (creg::BasicType*)type;
if (bt->id != creg::crInt && bt->id != creg::crFloat && bt->id != creg::crUChar && bt->id != creg::crBool) {
throw content_error("Projectile properties other than int, float and uchar, are not supported (" + script + ")");
return;
}
int p = 0;
while (p < script.length()) {
char opcode;
char c;
do { c = script[p++]; } while(c == ' ');
bool useInt=false;
if (c == 'i') opcode = OP_INDEX;
else if (c == 'r') opcode = OP_RAND;
else if (c == 'd') opcode = OP_DAMAGE;
else if (c == 'm') opcode = OP_SAWTOOTH;
else if (c == 'k') opcode = OP_DISCRETE;
else if (c == 's') opcode = OP_SINE;
else if (c == 'y') {opcode = OP_YANK; useInt=true;}
else if (c == 'x') {opcode = OP_MULTIPLY; useInt=true;}
else if (c == 'a') {opcode = OP_ADDBUFF; useInt=true;}
else if (c == 'p') opcode = OP_POW;
else if (c == 'q') {opcode = OP_POWBUFF; useInt=true;}
else if (isdigit(c) || c == '.' || c == '-') { opcode = OP_ADD; p--; }
else throw content_error("Explosion script error: \"" + script + "\" : \'" + string(1, c) + "\' is unknown opcode.");
char* endp;
if(!useInt) {
float v = (float)strtod(&script[p], &endp);
p += endp - &script[p];
code += opcode;
code.append((char*) &v, ((char*) &v) + 4);
}
else {
int v = (int)strtol(&script[p], &endp, 10);
if (v < 0 || v > 16) throw content_error("Explosion script error: \"" + script + "\" : Buffer index is out of bounds.");
p += endp - &script[p];
code += opcode;
code.append((char*) &v, ((char*) &v) + 4);
}
}
switch (bt->id) {
case creg::crInt: code.push_back(OP_STOREI); break;
case creg::crBool: code.push_back(OP_STOREI); break;
case creg::crFloat: code.push_back(OP_STOREF); break;
case creg::crUChar: code.push_back(OP_STOREC); break;
default:
throw content_error("Explosion script variable is of unsupported type. "
"Contact the Spring team to fix this.");
break;
}
Uint16 ofs = offset;
code.append((char*)&ofs, (char*)&ofs + 2);
}
else if (dynamic_cast<creg::ObjectInstanceType*>(type)) {
creg::ObjectInstanceType *oit = (creg::ObjectInstanceType *)type;
string::size_type start = 0;
for (creg::Class* c = oit->objectClass; c; c=c->base) {
for (int a=0;a<c->members.size();a++) {
string::size_type end = script.find(',', start+1);
ParseExplosionCode(psi, offset + c->members [a]->offset, c->members[a]->type, script.substr(start,end-start), code);
start = end+1;
if (start >= script.length()) break;
}
if (start >= script.length()) break;
}
}
else if (dynamic_cast<creg::StaticArrayBaseType*>(type)) {
creg::StaticArrayBaseType *sat = (creg::StaticArrayBaseType*)type;
string::size_type start = 0;
for (unsigned int i=0; i < sat->size; i++) {
string::size_type end = script.find(',', start+1);
ParseExplosionCode(psi, offset + sat->elemSize * i, sat->elemType, script.substr(start,end-start), code);
start = end+1;
if (start >= script.length()) break;
}
}
else {
if (type->GetName() == "AtlasedTexture*") {
string::size_type end = script.find(';', 0);
string texname = script.substr(0, end);
void* tex = ph->textureAtlas->GetTexturePtr(texname);
code += OP_LOADP;
code.append((char*)(&tex), ((char*)(&tex)) + sizeof(void*));
code += OP_STOREP;
Uint16 ofs = offset;
code.append((char*)&ofs, (char*)&ofs + 2);
}
else if (type->GetName() == "GroundFXTexture*") {
string::size_type end = script.find(';', 0);
string texname = script.substr(0, end);
void* tex = ph->groundFXAtlas->GetTexturePtr(texname);
code += OP_LOADP;
code.append((char*)(&tex), ((char*)(&tex)) + sizeof(void*));
code += OP_STOREP;
Uint16 ofs = offset;
code.append((char*)&ofs, (char*)&ofs + 2);
}
else if (type->GetName() == "CColorMap*") {
string::size_type end = script.find(';', 0);
string colorstring = script.substr(0, end);
void* colormap = CColorMap::LoadFromDefString(colorstring);
code += OP_LOADP;
code.append((char*)(&colormap), ((char*)(&colormap)) + sizeof(void*));
code += OP_STOREP;
Uint16 ofs = offset;
code.append((char*)&ofs, (char*)&ofs + 2);
}
else if (type->GetName() == "CExplosionGenerator*") {
string::size_type end = script.find(';', 0);
string name = script.substr(0, end);
void* explgen = explGenHandler->LoadGenerator(name);
code += OP_LOADP;
code.append((char*)(&explgen), ((char*)(&explgen)) + sizeof(void*));
code += OP_STOREP;
Uint16 ofs = offset;
code.append((char*)&ofs, (char*)&ofs + 2);
}
}
}
void CCustomExplosionGenerator::Load(CExplosionGeneratorHandler *h, const string& tag)
{
const LuaTable& root = h->GetTable();
const LuaTable expTable = root.SubTable(tag);
if (!expTable.IsValid()) {
throw content_error("Explosion info for " + tag + " not found.");
}
vector<string> spawns;
expTable.GetKeys(spawns);
ProjectileSpawnInfo *psi;
for (vector<string>::iterator si = spawns.begin(); si != spawns.end(); ++si) {
const string& spawnName = *si;
const LuaTable spawnTable = expTable.SubTable(spawnName);
if (!spawnTable.IsValid()) {
continue;
}
if (spawnName == "groundflash") {
continue;
}
psi = SAFE_NEW ProjectileSpawnInfo;
projectileSpawn.push_back(psi);
const string className = spawnTable.GetString("class", spawnName);
psi->projectileClass = h->projectileClasses.GetClass(className);
unsigned int flags = 0;
if (spawnTable.GetBool("ground", false)) { flags |= SPW_GROUND; }
if (spawnTable.GetBool("water", false)) { flags |= SPW_WATER; }
if (spawnTable.GetBool("air", false)) { flags |= SPW_AIR; }
if (spawnTable.GetBool("underwater", false)) { flags |= SPW_UNDERWATER; }
if (spawnTable.GetBool("unit", false)) { flags |= SPW_UNIT; }
if (spawnTable.GetBool("nounit", false)) { flags |= SPW_NO_UNIT; }
psi->flags = flags;
psi->count = spawnTable.GetInt("count", 1);
string code;
map<string, string> props;
map<string, string>::const_iterator propIt;
spawnTable.SubTable("properties").GetMap(props);
for (propIt = props.begin(); propIt != props.end(); ++propIt) {
creg::Class::Member* m = psi->projectileClass->FindMember(propIt->first.c_str());
if (m && (m->flags & creg::CM_Config)) {
ParseExplosionCode(psi, m->offset, m->type, propIt->second, code);
}
}
code += (char)OP_END;
psi->code.resize(code.size());
copy(code.begin(), code.end(), psi->code.begin());
}
const LuaTable gndTable = expTable.SubTable("groundflash");
const int ttl = gndTable.GetInt("ttl", 0);
if (ttl) {
groundFlash = SAFE_NEW GroundFlashInfo;
groundFlash->circleAlpha = gndTable.GetFloat("circleAlpha", 0.0f);
groundFlash->flashSize = gndTable.GetFloat("flashSize", 0.0f);
groundFlash->flashAlpha = gndTable.GetFloat("flashAlpha", 0.0f);
groundFlash->circleGrowth = gndTable.GetFloat("circleGrowth", 0.0f);
groundFlash->color = gndTable.GetFloat3("color", float3(1.0f, 1.0f, 0.8f));
unsigned int flags = SPW_GROUND;
if (gndTable.GetBool("ground", false)) { flags |= SPW_GROUND; }
if (gndTable.GetBool("water", false)) { flags |= SPW_WATER; }
if (gndTable.GetBool("air", false)) { flags |= SPW_AIR; }
if (gndTable.GetBool("underwater", false)) { flags |= SPW_UNDERWATER; }
if (gndTable.GetBool("unit", false)) { flags |= SPW_UNIT; }
if (gndTable.GetBool("nounit", false)) { flags |= SPW_NO_UNIT; }
groundFlash->flags = flags;
groundFlash->ttl = ttl;
}
useDefaultExplosions = expTable.GetBool("useDefaultExplosions", false);
}
void CCustomExplosionGenerator::Explosion(const float3 &pos, float damage, float radius, CUnit *owner,float gfxMod, CUnit *hit,const float3 &dir)
{
float h2 = ground->GetHeight2(pos.x, pos.z);
unsigned int flags = 0;
if (pos.y - max(0.0f, h2) > 20) flags = SPW_AIR;
else if (h2 < -3) flags = SPW_WATER;
else if (pos.y < -15) flags = SPW_UNDERWATER;
else flags = SPW_GROUND;
if (hit) flags |= SPW_UNIT;
else flags |= SPW_NO_UNIT;
for (int a = 0; a < projectileSpawn.size(); a++) {
ProjectileSpawnInfo *psi = projectileSpawn[a];
if (!(psi->flags & flags))
continue;
for (int c = 0; c < psi->count; c++) {
CExpGenSpawnable *projectile = (CExpGenSpawnable*)psi->projectileClass->CreateInstance();
ExecuteExplosionCode(&psi->code[0], damage, (char*)projectile, c, dir);
projectile->Init(pos, owner);
}
}
if ((flags & SPW_GROUND) && groundFlash)
SAFE_NEW CStandardGroundFlash(pos, groundFlash->circleAlpha, groundFlash->flashAlpha, groundFlash->flashSize, groundFlash->circleGrowth, groundFlash->ttl, groundFlash->color);
if (useDefaultExplosions)
CStdExplosionGenerator::Explosion(pos, damage, radius, owner, gfxMod, hit, dir);
}
void CCustomExplosionGenerator::OutputProjectileClassInfo()
{
const vector<creg::Class*>& classes = creg::System::GetClasses();
ofstream fs("projectiles.txt");
CExplosionGeneratorHandler egh;
if (fs.bad() || !fs.is_open())
return;
for (vector<creg::Class*>::const_iterator ci = classes.begin(); ci != classes.end(); ++ci)
{
if (!(*ci)->IsSubclassOf (CExpGenSpawnable::StaticClass()) || (*ci) == CExpGenSpawnable::StaticClass())
continue;
creg::Class *klass = *ci;
fs << "Class: " << klass->name << ". Scriptname: " << egh.projectileClasses.FindAlias(klass->name) << endl;
for (;klass;klass=klass->base) {
for (unsigned int a=0;a<klass->members.size();a++)
{
if (klass->members[a]->flags & creg::CM_Config)
fs << "\t" << klass->members[a]->name << ": " << klass->members[a]->type->GetName() << "\n";
}
}
fs << "\n\n";
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?