Copy to Clipboard Test

Chain Chomp Code

const int SFX_CHOMP = 89; // Sound the chain chomp makes when it charges

@InitD0("Num Links"),
@InitDHelp0("How many chain links the chomp has. This determines its leash distance.")
npc script Chainchomp{
	using namespace NPCAnim;
	void run(int numLinks){
		if(numLinks==0)
			numLinks = 8;
		numLinks = Clamp(numLinks, 3, 32);
		++numLinks;
		int maxDist = (numLinks-1) * 8;
		
		Waitspawn(this);
		
		AnimHandler aptr = new AnimHandler(this);
		aptr->AddAnim(0, 0, 1, 1, ADF_8WAY);
		
		int homeX = this->X;
		int homeY = this->Y;
		int chainX[33];
		int chainY[33];
		for(int i=0; i<33; i++){
			chainX[i] = this->X;
			chainY[i] = this->Y;
		}
		
		int vars[16] = {chainX, chainY, numLinks};
		int chompAngle;
		ChompWaitframe(this, vars, 10);
		this->MoveFlags[NPCMV_IGNORE_SOLIDITY] = true;
		this->MoveFlags[NPCMV_OBEYS_GRAVITY] = true;
		this->MoveFlags[NPCMV_CAN_PITFALL] = false;
		this->MoveFlags[NPCMV_CAN_PIT_WALK] = true;
		this->MoveFlags[NPCMV_CAN_WATERDROWN] = false;
		this->MoveFlags[NPCMV_CAN_WATER_WALK] = true;
		while(true){
			int numHops = Rand(4, 6);
			// Do 4-6 hops, keep hopping until within the home distance
			for(int i=0; i<numHops||Distance(this->X, this->Y, homeX, homeY)>=7*vars[2]; i++){
				if(Distance(this->X, this->Y, homeX, homeY)<maxDist)
					chompAngle = Rand(360);
				else
					chompAngle = Angle(this->X, this->Y, homeX, homeY)+Rand(-45, 45);
				this->Jump = 1;
				while(this->Jump>0||this->Z>0){
					this->MoveAtAngle(chompAngle, this->Step/100, SPW_FLOATER);
					this->Dir = AngleDir8(WrapDegrees(chompAngle));
					ChompWaitframe(this, vars);
				}
				// 1/3 of the time, pause after a hop
				if(Rand(3)==0){
					ChompWaitframe(this, vars, 20);
				}
			}
			// If Link is within 40 pixels of the home distance, do a charge
			if(Distance(Link->X, Link->Y, homeX, homeY)<maxDist+40){
				chompAngle = Angle(this->X, this->Y, Link->X, Link->Y);
				bool cancharge = true;
				int X = this->X;
				int Y = this->Y;
				bool obeyNoEnemy = this->MoveFlags[NPCMV_IGNORE_BLOCKFLAGS];
				this->MoveFlags[NPCMV_IGNORE_BLOCKFLAGS] = true;
				// Project the charge to see if it passes over no enemy combos
				for(int i=0; i<60&&Distance(this->X, this->Y, homeX, homeY)<maxDist; i++){
					this->MoveAtAngle(chompAngle, this->Step/100*2.6666, SPW_FLOATER);
					if(ComboFI(this->X+8, this->Y+8, 96))
						cancharge = false;
				}
				this->X = X;
				this->Y = Y;
				this->MoveFlags[NPCMV_IGNORE_BLOCKFLAGS] = obeyNoEnemy;
				// Do the charge if able
				if(cancharge){
					ChompWaitframe(this, vars, 10);
					Game->PlaySound(SFX_CHOMP);
					for(int i=0; i<60&&Distance(this->X, this->Y, homeX, homeY)<maxDist; i++){
						this->MoveAtAngle(chompAngle, this->Step/100*2.6666, SPW_FLOATER);
						this->Dir = AngleDir8(WrapDegrees(chompAngle));
						ChompWaitframe(this, vars);
					}
					ChompWaitframe(this, vars, 90);
				}
			}
		}
	}
	void UpdateChain(npc this, int vars){
		AnimHandler aptr = GetAnimHandler(this);
		int til = aptr->OriginalTile + 8;
		
		int Combo = this->Attributes[10];
		int chainX = vars[0];
		int chainY = vars[1];
		int numLinks = vars[2];
		int vX[33];
		int vY[33];
		int sz = SizeOfArray(chainX);
		for(int i=1; i<numLinks-1; i++){
			vX[i] = 0;
			vY[i] = 0;
			float d1 = Distance(chainX[i], chainY[i], chainX[i+1], chainY[i+1]);
			float a1 = Angle(chainX[i], chainY[i], chainX[i+1], chainY[i+1]);
			float d2 = Distance(chainX[i], chainY[i], chainX[i-1], chainY[i-1]);
			float a2 = Angle(chainX[i], chainY[i], chainX[i-1], chainY[i-1]);
			if(d1>=8||d2>=8){
				vX[i] += VectorX(d1/4, a1) + VectorX(d2/4, a2);
				vY[i] += VectorY(d1/4, a1) + VectorY(d2/4, a2);
			}
		}
		
		for(int i=1; i<numLinks; i++){
			chainX[i] += vX[i];
			chainY[i] += vY[i];
			if(Link->HP>0)
				Screen->FastTile(SPLAYER_EWEAP_BEHIND_DRAW, chainX[i], chainY[i], til, this->CSet, OP_OPAQUE);
		}
	}
	void ChompWaitframe(npc this, int vars, int frames=1)
	{
		for(int i=0; i<frames; ++i)
		{
			int chainX = vars[0];
			int chainY = vars[1];
			chainX[0] = this->X;
			chainY[0] = this->Y-this->Z;
			UpdateChain(this, vars);
			Waitframe(this);
		}
	}
}