cobinstance.cpp

来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,724 行 · 第 1/4 页

CPP
1,724
字号
#include "StdAfx.h"
#include "CobEngine.h"
#include "CobFile.h"
#include "CobInstance.h"
#include "CobThread.h"

#ifndef _CONSOLE

#include <SDL_types.h>
#include "Game/GameHelper.h"
#include "LogOutput.h"
#include "Map/Ground.h"
#include "Rendering/UnitModels/3DOParser.h"
#include "Rendering/UnitModels/s3oParser.h"
#include "Sim/Misc/LosHandler.h"
#include "Sim/Misc/RadarHandler.h"
#include "Sim/MoveTypes/AirMoveType.h"
#include "Sim/MoveTypes/MoveType.h"
#include "Sim/Projectiles/ExplosionGenerator.h"
#include "Sim/Projectiles/PieceProjectile.h"
#include "Sim/Projectiles/ProjectileHandler.h"
#include "Sim/Projectiles/Unsynced/BubbleProjectile.h"
#include "Sim/Projectiles/Unsynced/HeatCloudProjectile.h"
#include "Sim/Projectiles/Unsynced/MuzzleFlame.h"
#include "Sim/Projectiles/Unsynced/SmokeProjectile.h"
#include "Sim/Projectiles/Unsynced/WakeProjectile.h"
#include "Sim/Projectiles/Unsynced/WreckProjectile.h"
#include "Sim/Units/CommandAI/CommandAI.h"
#include "Sim/Units/CommandAI/Command.h"
#include "Sim/Units/UnitDef.h"
#include "Sim/Units/Unit.h"
#include "Sim/Units/UnitHandler.h"
#include "Sim/Units/UnitTypes/TransportUnit.h"
#include "Sim/Weapons/PlasmaRepulser.h"
#include "Sim/Weapons/WeaponDefHandler.h"
#include "Sim/Weapons/Weapon.h"
#include "Sound.h"
#include "Sync/SyncTracer.h"
#include "mmgr.h"

#endif


// Indices for set/get value
#define ACTIVATION           1  // set or get
#define STANDINGMOVEORDERS   2  // set or get
#define STANDINGFIREORDERS   3  // set or get
#define HEALTH               4  // get (0-100%)
#define INBUILDSTANCE        5  // set or get
#define BUSY                 6  // set or get (used by misc. special case missions like transport ships)
#define PIECE_XZ             7  // get
#define PIECE_Y              8  // get
#define UNIT_XZ              9  // get
#define UNIT_Y              10  // get
#define UNIT_HEIGHT         11  // get
#define XZ_ATAN             12  // get atan of packed x,z coords
#define XZ_HYPOT            13  // get hypot of packed x,z coords
#define ATAN                14  // get ordinary two-parameter atan
#define HYPOT               15  // get ordinary two-parameter hypot
#define GROUND_HEIGHT       16  // get land height, 0 if below water
#define BUILD_PERCENT_LEFT  17  // get 0 = unit is built and ready, 1-100 = How much is left to build
#define YARD_OPEN           18  // set or get (change which plots we occupy when building opens and closes)
#define BUGGER_OFF          19  // set or get (ask other units to clear the area)
#define ARMORED             20  // set or get

/*#define WEAPON_AIM_ABORTED  21
#define WEAPON_READY        22
#define WEAPON_LAUNCH_NOW   23
#define FINISHED_DYING      26
#define ORIENTATION         27*/
#define IN_WATER            28
#define CURRENT_SPEED       29
//#define MAGIC_DEATH         31
#define VETERAN_LEVEL       32
#define ON_ROAD             34

#define MAX_ID                    70
#define MY_ID                     71
#define UNIT_TEAM                 72
#define UNIT_BUILD_PERCENT_LEFT   73
#define UNIT_ALLIED               74
#define MAX_SPEED                 75
#define CLOAKED                   76
#define WANT_CLOAK                77
#define GROUND_WATER_HEIGHT       78 // get land height, negative if below water
#define UPRIGHT                   79 // set or get
#define	POW                       80 // get
#define PRINT                     81 // get, so multiple args can be passed
#define HEADING                   82 // get
#define TARGET_ID                 83 // get
#define LAST_ATTACKER_ID          84 // get
#define LOS_RADIUS                85 // set or get
#define AIR_LOS_RADIUS            86 // set or get
#define RADAR_RADIUS              87 // set or get
#define JAMMER_RADIUS             88 // set or get
#define SONAR_RADIUS              89 // set or get
#define SONAR_JAM_RADIUS          90 // set or get
#define SEISMIC_RADIUS            91 // set or get
#define DO_SEISMIC_PING           92 // get
#define CURRENT_FUEL              93 // set or get
#define TRANSPORT_ID              94 // get
#define SHIELD_POWER              95 // set or get
#define STEALTH                   96 // set or get
#define CRASHING                  97 // set or get, returns whether aircraft isCrashing state
#define CHANGE_TARGET             98 // set, the value it's set to determines the affected weapon
#define CEG_DAMAGE                99 // set
#define COB_ID                   100 // get
#define PLAY_SOUND				 101 // get, so multiple args can be passed
#define KILL_UNIT                102 // get KILL_UNIT(unitId, SelfDestruct=true, Reclaimed=false)
#define ALPHA_THRESHOLD          103 // set or get
#define SET_WEAPON_UNIT_TARGET   106 // get (fake set)
#define SET_WEAPON_GROUND_TARGET 107 // get (fake set)

// NOTE: [LUA0 - LUA9] are defined in CobThread.cpp as [110 - 119]

#define FLANK_B_MODE             120 // set or get
#define FLANK_B_DIR              121 // set or get, set is through get for multiple args
#define FLANK_B_MOBILITY_ADD     122 // set or get
#define FLANK_B_MAX_DAMAGE       123 // set or get
#define FLANK_B_MIN_DAMAGE       124 // set or get
#define WEAPON_RELOADSTATE       125 // get (with fake set)
#define WEAPON_RELOADTIME        126 // get (with fake set)
#define WEAPON_ACCURACY          127 // get (with fake set)
#define WEAPON_SPRAY             128 // get (with fake set)
#define WEAPON_RANGE             129 // get (with fake set)
#define WEAPON_PROJECTILE_SPEED  130 // get (with fake set)

// NOTE: shared variables use codes [1024 - 5119]

int CCobInstance::teamVars[MAX_TEAMS][TEAM_VAR_COUNT] = {{ 0 }};
int CCobInstance::allyVars[MAX_TEAMS][ALLY_VAR_COUNT] = {{ 0 }};
int CCobInstance::globalVars[GLOBAL_VAR_COUNT]        =  { 0 };


CCobInstance::CCobInstance(CCobFile& _script, CUnit* _unit)
: script(_script)
{
	for (int i = 0; i < script.numStaticVars; ++i) {
		staticVars.push_back(0);
	}
	for (unsigned int i = 0; i < script.pieceNames.size(); ++i) {
		struct PieceInfo pi;

		//init from model?
		pi.coords[0] = 0; pi.coords[1] = 0; pi.coords[2] = 0;
		pi.rot[0] = 0; pi.rot[1] = 0; pi.rot[2] = 0;
		pi.name = script.pieceNames[i];
		pi.updated = false;
		pi.visible = true;

		pieces.push_back(pi);
	}

	for (int i = 0; i < UNIT_VAR_COUNT; i++) {
		unitVars[i] = 0;
	}

	unit = _unit;
//	int mo = unit->pos.x;

	yardOpen = false;
	busy = false;
	smoothAnim = unit->unitDef->smoothAnim;
}

CCobInstance::~CCobInstance(void)
{
	//Can't delete the thread here because that would confuse the scheduler to no end
	//Instead, mark it as dead. It is the function calling Tick that is responsible for delete.
	//Also unregister all callbacks
	for (list<CCobThread *>::iterator i = threads.begin(); i != threads.end(); ++i) {
		(*i)->state = CCobThread::Dead;
		(*i)->SetCallback(NULL, NULL, NULL);
	}

	// Remove us from possible animation ticking (should only be needed when anims.size() > 0
	GCobEngine.RemoveInstance(this);

	for (list<struct AnimInfo *>::iterator i = anims.begin(); i != anims.end(); ++i) {

		//All threads blocking on animations can be killed safely from here since the scheduler does not
		//know about them
		for (list<CCobThread *>::iterator j = (*i)->listeners.begin(); j != (*i)->listeners.end(); ++j) {
			delete *j;
		}
		delete *i;
	}
}
int CCobInstance::Call(const string &fname)
{
	vector<int> x;
	return Call(fname, x, NULL, NULL, NULL);
}

int CCobInstance::Call(const string &fname, vector<int> &args)
{
	return Call(fname, args, NULL, NULL, NULL);
}

int CCobInstance::Call(const string &fname, int p1)
{
	vector<int> x;
	x.push_back(p1);
	return Call(fname, x, NULL, NULL, NULL);
}

int CCobInstance::Call(const string &fname, CBCobThreadFinish cb, void *p1, void *p2)
{
	vector<int> x;
	return Call(fname, x, cb, p1, p2);
}

int CCobInstance::Call(const string &fname, vector<int> &args, CBCobThreadFinish cb, void *p1, void *p2)
{
	int fn = script.getFunctionId(fname);
	if (fn == -1) {
		//logOutput.Print("CobError: unknown function %s called by user", fname.c_str());
		return -1;
	}

	return RealCall(fn, args, cb, p1, p2);
}

int CCobInstance::Call(int id)
{
	vector<int> x;
	return Call(id, x, NULL, NULL, NULL);
}

int CCobInstance::Call(int id, int p1)
{
	vector<int> x;
	x.push_back(p1);
	return Call(id, x, NULL, NULL, NULL);
}

int CCobInstance::Call(int id, vector<int> &args)
{
	return Call(id, args, NULL, NULL, NULL);
}

int CCobInstance::Call(int id, CBCobThreadFinish cb, void *p1, void *p2)
{
	vector<int> x;
	return Call(id, x, cb, p1, p2);
}

int CCobInstance::Call(int id, vector<int> &args, CBCobThreadFinish cb, void *p1, void *p2)
{
	int fn = script.scriptIndex[id];
	if (fn == -1) {
		//logOutput.Print("CobError: unknown function index %d called by user", id);
		if(cb){
			(*cb)(0, p1, p2);	//in case the function doesnt exist the callback should still be called
		}
		return -1;
	}

	return RealCall(fn, args, cb, p1, p2);
}


int CCobInstance::RawCall(int fn, vector<int> &args)
{
	return RawCall(fn, args, NULL, NULL, NULL);
}


int CCobInstance::RawCall(int fn, vector<int> &args, CBCobThreadFinish cb, void *p1, void *p2)
{
	if ((fn < 0) || (fn >= script.scriptNames.size())) {
		if (cb) {
			// in case the function doesnt exist the callback should still be called
			(*cb)(0, p1, p2);
		}
		return -1;
	}
	return RealCall(fn, args, cb, p1, p2);
}


//Returns 0 if the call terminated. If the caller provides a callback and the thread does not terminate,
//it will continue to run. Otherwise it will be killed. Returns 1 in this case.
int CCobInstance::RealCall(int functionId, vector<int> &args, CBCobThreadFinish cb, void *p1, void *p2)
{
	CCobThread *t = SAFE_NEW CCobThread(script, this);
	t->Start(functionId, args, false);

#if COB_DEBUG > 0
	if (COB_DEBUG_FILTER)
		logOutput.Print("Calling %s:%s", script.name.c_str(), script.scriptNames[functionId].c_str());
#endif

	int res = t->Tick(30);
	t->CommitAnims(30);

	//Make sure this is run even if the call terminates instantly
	if (cb)
		t->SetCallback(cb, p1, p2);

	if (res == -1) {
		unsigned int i = 0, argc = t->CheckStack(args.size());
		//Retrieve parameter values from stack
		for (; i < argc; ++i)
			args[i] = t->GetStackVal(i);
		//Set erroneous parameters to 0
		for (; i < args.size(); ++i)
			args[i] = 0;
		delete t;
		return 0;
	}
	else {
		//It has already added itself to the correct scheduler (global for sleep, or local for anim)
		return 1;
	}
}


//Updates cur, returns 1 if destination was reached, 0 otherwise
int CCobInstance::MoveToward(int &cur, int dest, int speed)
{
	if (dest > cur) {
		cur += speed;
		if (cur > dest) {
			cur = dest;
			return 1;
		}
	}
	else {
		cur -= speed;
		if (cur < dest) {
			cur = dest;
			return 1;
		}
	}

	return 0;
}

//Updates cur, returns 1 if destination was reached, 0 otherwise
int CCobInstance::TurnToward(int &cur, int dest, int speed)
{
	short int delta = dest - cur;
	if (delta > 0) {
		if (delta <= speed) {
			cur = dest;
			return 1;
		}
		cur += speed;
	}
	else {
		if (delta >= -speed) {
			cur = dest;
			return 1;
		}
		cur -= speed;
	}
	cur %= 65536;

	//logOutput.Print("turning %d %d %d", cur, dest, speed);

	return 0;
}

//Dest is not the final angle (obviously) but the final desired speed
//Returns 1 if the desired speed is 0 and it is reached, otherwise 0
//Speed is updated if it is not equal to dest
//Divisor is the deltatime, it is not added before the call because speed may have to be updated
int CCobInstance::DoSpin(int &cur, int dest, int &speed, int accel, int divisor)
{
	//Check if we are not at the final speed
	if (speed != dest) {
		speed += accel * 30 / divisor;		//TA obviously defines accelerations in speed/frame (at 30 fps)
		if (accel > 0) {
			if (speed > dest)
				speed = dest;		//We are accelerating, make sure we dont go past desired speed
		}
		else {
			if (speed < dest)
				speed = dest;		//Decelerating
			if (speed == 0)
				return 1;
		}
	}

	//logOutput.Print("Spinning with %d %d %d %d", dest, speed, accel, divisor);

	cur += speed / divisor;
	cur %= 65536;

	return 0;
}

// Unblocks all threads waiting on this animation
void CCobInstance::UnblockAll(struct AnimInfo * anim)
{
	list<CCobThread *>::iterator li;

	for (li = anim->listeners.begin(); li != anim->listeners.end(); ++li) {
		//Not sure how to do this more cleanly.. Will probably rewrite it
		if (((*li)->state == CCobThread::WaitMove) ||((*li)->state == CCobThread::WaitTurn)) {
			(*li)->state = CCobThread::Run;
			GCobEngine.AddThread(*li);
		}
		else if ((*li)->state == CCobThread::Dead) {
			delete *li;
		}
		else {
			logOutput.Print("CobError: Turn/move listenener in strange state %d", (*li)->state);
		}
	}
}

//Called by the engine when we are registered as animating. If we return -1 it means that
//there is no longer anything animating
int CCobInstance::Tick(int deltaTime)
{
	int done;
	list<struct AnimInfo *>::iterator it = anims.begin();
	list<struct AnimInfo *>::iterator cur;

	while (it != anims.end()) {
		//Advance it, so we can erase cur safely
		cur = it++;

		done = false;
		pieces[(*cur)->piece].updated = true;

		switch ((*cur)->type) {
			case AMove:
				done = MoveToward(pieces[(*cur)->piece].coords[(*cur)->axis], (*cur)->dest, (*cur)->speed / (1000 / deltaTime));

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?