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 + -
显示快捷键?