Downloads containing WebGun.asc

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Anniversary Bash 26 CTF Jazz2Online Capture the flag N/A Download file

File preview

#pragma require "WebGun.asc" //Scripted by Naps
#include "MLLE-Weapons.asc"
#pragma require "WebGun.j2a" //Spritework by Lynx
#pragma offer "WebGunFire.wav"
#pragma offer "WebGunWait.wav"
#pragma offer "WebGunBouncePlayer.wav"

namespace NapsWeapons {
	array<array<jjOBJ@>> Webs(33);
	bool clientRequestedWebs = false;
	class WebGun : MLLEWeapons::WeaponInterface {
		bool BouncyPU = true;
		uint8 EnhancedAirJump = 0;
		bool SelfEntrap = true;
		int MaxWeb = 0;
		uint currentMaxWeb = 0;
		uint WebCounterEnd = 30; //seconds
		uint WebPUCounterEnd = 60; //seconds
		WebGun() {
			super(
				regularObjectTemplate: MLLEWeapons::ObjectTemplate(
					xSpeed: 5,
					xAcc: 0,
					animSpeed: 2,
					killAnim: 6,
					curAnim: 0,
					lightType: LIGHT::POINT2,
					counterEnd: 30,
					scriptedCollisions: true,
					playerHandling: HANDLING::SPECIAL,
					bulletHandling: HANDLING::DETECTBULLET
				),
				powerupObjectTemplate: MLLEWeapons::ObjectTemplate(
					xSpeed: 5,
					xAcc: 0,
					animSpeed: 3,
					killAnim: 7,
					curAnim: 4,
					lightType: LIGHT::POINT2,
					counterEnd: 60,
					scriptedCollisions: true,
					playerHandling: HANDLING::SPECIAL,
					bulletHandling: HANDLING::DETECTBULLET
				),
				style: WEAPON::MISSILE,
				animSetFilename: "WebGun.j2a",
				sampleFilenames: array<string> = {"WebGunFire.wav","WebGunWait.wav","WebGunBouncePlayer.wav"},
				pickupAnimation: 1,
				poweredUpPickupAnimation: 6,
				ammoCrateAnimation: 2,
				powerupAnimation: 3,
				traits: se::weapon_is_effective_against_players | se::weapon_is_effective_against_sp_enemies | se::weapon_supports_mouse_aim | se::weapon_works_in_all_modes | se::weapon_works_in_mp | se::weapon_works_in_sp | se::weapon_works_in_coop | se::weapon_works_online | se::weapon_has_all_pickups | se::weapon_fails_underwater,
				behavior: MLLEWeapons::behaviorFunction(DetermineBehavior),
				onMain: se::MainCallback(MainSetup),
				onDrawAmmo: se::DrawingCallback(DrawLimit),
				onReceive: se::PacketCallback(webPacket),
				apply: MLLEWeapons::applyFunction(ApplyCustomParameters)
			);
		}
		uint thisSetID = SetID;
		array<SOUND::Sample> thisSamples(3);
		WebGun@ selfReference = this;
		int lastTimeSinceSoundPlayed = 0;
		void DetermineBehavior(jjOBJ@ obj, bool powerup) const {
			if (obj.creatorType == CREATOR::PLAYER && jjPlayers[obj.creatorID].isLocal)
				jjSample(obj.xPos, obj.yPos, Samples[0],64, powerup? 20000 : 28000);
			jjOBJ@ o = obj;
			obj.behavior = Web(o,selfReference);
			if (!powerup) {
				obj.counterEnd = WebCounterEnd;
			} else {
				obj.counterEnd = WebPUCounterEnd;
			}
		}
		
		bool DrawLimit(jjPLAYER@ player, jjCANVAS@ canvas, const jjANIMATION@ anim) const {
			if (player !is null && !player.noFire && player.charCurr != CHAR::FROG && player.charCurr != CHAR::BIRD && MaxWeb != 0) {
				int x, y;
				bool tinyText = false;
				if (::jjSubscreenWidth > 400) {
					x = ::jjSubscreenWidth - 28;
					y = ::jjSubscreenHeight - 54;
				} else {
					x = ::jjSubscreenWidth - 8;
					y = ::jjSubscreenHeight - 34;
					tinyText = true;
				}
				string text = Webs[player.playerID].length() + "/" + currentMaxWeb;
				if (Webs[player.playerID].length() > currentMaxWeb) {
					text = currentMaxWeb + "/" + currentMaxWeb;
				}
				int textSize = jjGetStringWidth(text,tinyText? STRING::SMALL : STRING::MEDIUM,STRING::NORMAL);
				canvas.drawString(x - textSize, y,text,tinyText? STRING::SMALL : STRING::MEDIUM);
			}
			return false;
		}
		
		uint lastWebCountChange = 0;
		void MainSetup(int) {
			if (MaxWeb < 0) {
				uint count = playersInGame();
				if (count < 1) count = 1;
				currentMaxWeb = uint(abs(MaxWeb) / count);
			} else currentMaxWeb = MaxWeb;
			if (!clientRequestedWebs && !jjIsServer) {
				jjSTREAM packet = ConstructPacket();
				jjSendPacket(packet);
				clientRequestedWebs = true;
			}
			
		}
		
		uint8 playersInGame() {
			uint8 playerCount = 0;
			for (int i = 0;i < 32;i++) {
				jjPLAYER@ play = jjPlayers[i];
				if (play.isInGame) playerCount++;
			}
			return playerCount;
		}
		
		void webPacket(jjSTREAM& packet, int clientID) {
			if (jjIsServer) {
				for (int i = 0;i < 32;i++ ) {
					jjPLAYER@ play = jjPlayers[i];
					
					
					if (Webs[i].length == 0) continue;
					for (uint j = 0;j < Webs[i].length;j++) {
						jjSTREAM replyPacket = ConstructPacket();
						replyPacket.push(i);
						jjOBJ@ o = Webs[i][j];
						replyPacket.push(o.xPos);
						replyPacket.push(o.yPos);
						bool placed = o.state == STATE::FLY? false : true;
						replyPacket.push(o.var[2]);
						replyPacket.push(o.var[6]);
						replyPacket.push(o.justHit);
						if (!placed) {
							replyPacket.push(false);
							replyPacket.push(o.frameID);
							replyPacket.push(o.counter);
						} else {
							replyPacket.push(true);
							replyPacket.push(o.counter);
						}
						jjSendPacket(replyPacket,clientID);
					}
				}
				
			} else {
					int playerID = 0;
					packet.pop(playerID);
					float x,y;
					bool placed = false;
					packet.pop(x);
					packet.pop(y);
					jjOBJ@ o = jjObjects[jjAddObject(OBJECT::BULLET, x,y, playerID, CREATOR::PLAYER, BEHAVIOR::INACTIVE)];
					o.behavior = Web(o,selfReference);
					o.playerHandling = HANDLING::SPECIAL;
					o.bulletHandling = HANDLING::DETECTBULLET;
					o.scriptedCollisions = true;
					packet.pop(o.var[2]);
					packet.pop(o.var[6]);
					packet.pop(o.justHit);
					if (!MLLEWeapons::HelpfulBulletFunctions::IsPowerup(o)) {
						o.counterEnd = WebCounterEnd;
					} else {
						o.counterEnd = WebPUCounterEnd;
					}
					packet.pop(placed);
					o.xSpeed = 5;
					if (!placed) {
						o.state = STATE::FLY;
						
						o.determineCurAnim(SetID,!MLLEWeapons::HelpfulBulletFunctions::IsPowerup(o)? 0 : 4);
						packet.pop(o.frameID);
						packet.pop(o.counter);
					} else {
						o.state = STATE::WAIT;
						o.determineCurAnim(SetID,!MLLEWeapons::HelpfulBulletFunctions::IsPowerup(o)? 1 : 6);
						packet.pop(o.counter);
					}
					o.var[0] = int(Webs[o.creatorID].length());
					if (jjGameState == GAME::STOPPED) {
						o.var[5] = 1;
					}
					if (jjGameState == GAME::OVERTIME) {
						o.var[5] = 2;
					}
					o.var[8] = determineTeam(o,jjPlayers[playerID]);
					Webs[o.creatorID].insertLast(@o);
			}
		}
		
	
		
		bool ApplyCustomParameters(uint, se::WeaponHook@, jjSTREAM@ parameter) {
			if (parameter !is null && parameter.getSize() >= 1) {
				parameter.pop(BouncyPU);
				parameter.pop(EnhancedAirJump);
				parameter.pop(SelfEntrap);
				parameter.pop(MaxWeb);
				parameter.pop(WebCounterEnd);
				parameter.pop(WebPUCounterEnd);
			}
			return true;
		}
		
		SOUND::Sample determineSample(int ID) {
			return Samples[ID];
		}
		uint determineSetID() {
			return SetID;
		}
		void resortList(int playerID, uint startID) {
			for (uint i = startID + 1;i < Webs[playerID].length();i++) {
				Webs[playerID][i].var[0] = Webs[playerID][i].var[0] - 1;
			}
		}
		int determineTeam(jjOBJ@ obj,jjPLAYER@ play) {
			if (obj.creatorType != CREATOR::PLAYER) return -1;
			if (play.isJailed) return 5;
			if (jjGameMode == GAME::CTF) {
				return play.team + 1;
			}
			if (jjGameCustom == GAME::RT) {
				if (play is jjBottomFeeder) return 6;
				if (play is jjTokenOwner) return 7;
			}
			if (play.isZombie) return 8;
			
			return 0;
		}
	}
	class Web : jjBEHAVIORINTERFACE {
		jjOBJ@ obj;
		WebGun@ weapon;
		bool objectIsExploded = false;
		Web(jjOBJ@ originalOBJ,WebGun@ w) {@obj = @originalOBJ; @weapon = @w;}
		bool isPowerup(jjOBJ@ obj) {
			return (obj.var[6] & 8) == 8;
		}
		
		void onBehave(jjOBJ@) {
			jjPLAYER@ creator = jjPlayers[obj.creatorID];
			if (obj.state == STATE::START) {
				obj.state = STATE::FLY;
				
				obj.var[0] = int(Webs[obj.creatorID].length());
				if (jjGameState == GAME::STOPPED) {
					obj.var[5] = 1;
				}
				if (jjGameState == GAME::OVERTIME) {
					obj.var[5] = 2;
				}
				obj.var[8] = weapon.determineTeam(obj,creator);
				Webs[obj.creatorID].insertLast(@obj);
			} else if (obj.state == STATE::FLY) {
				obj.xPos += obj.xSpeed;
				obj.yPos += obj.ySpeed;
				obj.counter++;
				uint teamColor = determineTeamColor(obj,creator);
				
				MLLEWeapons::HelpfulBulletFunctions::DrawAngled(obj,1,1,teamColor == 0? SPRITE::NORMAL : SPRITE::SINGLEHUE,teamColor);
				if (isPowerup(obj)) {
					uint teamColor2 = determineTeamColor2(obj,creator);
					jjDrawRotatedSprite(obj.xPos, obj.yPos, weapon.determineSetID(),5,obj.frameID, MLLEWeapons::HelpfulBulletFunctions::GetAngle(obj), MLLEWeapons::HelpfulBulletFunctions::GetDirection(obj) * 1, 1, teamColor2 == 0? SPRITE::NORMAL : SPRITE::SINGLEHUE,teamColor2);
				}
				if (obj.counter % 5 == 0) {
					obj.frameID++;
				}
				if (MLLEWeapons::HelpfulBulletFunctions::MaskedPixel(obj)) {
					obj.frameID = 5;
				}
				for (uint i = 0; i < 32; ++i) {
					const jjPLAYER@ target = jjPlayers[i];
					if (!target.isInGame)
						continue;
					if (!MLLEWeapons::HelpfulBulletFunctions::PlayerIsEnemy(obj,target))
						continue;
					if (target.blink != 0)
						continue;
					if (obj.doesCollide(target)) {
						obj.frameID = 5;
					}
				}
				if (obj.frameID == 5) {
					jjSample(obj.xPos, obj.yPos, weapon.determineSample(1),64,0);
					obj.counter = 0;
					obj.frameID = 0;
					obj.state = STATE::WAIT;
					obj.determineCurAnim(weapon.determineSetID(),!isPowerup(obj)? 1 : 6);
				}
				
				
			} else if (obj.state == STATE::WAIT) {
				obj.isBlastable = false;
				if (jjGameState != GAME::PAUSED) obj.counter++;
				if (obj.var[2] < 70*5 && jjGameState != GAME::PAUSED) obj.var[2] = obj.var[2] + 1;
				obj.lightType = LIGHT::NONE;
				
				obj.causesRicochet = false;
				if (obj.justHit == 0) {
					if (jjGameMode <= GAME::COOP) {
						for (int i = 0; i < jjObjectCount; i++) {
							jjOBJ@ target = jjObjects[i];
							if (!target.isActive)
								continue;
							if (target.playerHandling != HANDLING::ENEMY) 
								continue;
							target.freeze = 70;
						}
					}
					uint teamColor = determineTeamColor(obj,creator);
					int brightness = 0;
					if (teamColor == 0) {
						
						if (weapon.SelfEntrap && obj.var[2] < 70*3) {
							brightness = 87 + int(jjCos((obj.var[2]*20) % 1023)*87);
						} else {
							if (obj.counter % 10 == 0) {
								obj.frameID++;
							}
							if (obj.frameID >= 4) {
								obj.frameID = 0;
							}
							brightness = 175;
						}
						
						jjDrawSpriteFromCurFrame(obj.xPos,obj.yPos,obj.curFrame,obj.direction,SPRITE::BRIGHTNESS,brightness,3);
					} else {
						
						if (weapon.SelfEntrap && obj.var[2] < 70*3) {
							brightness = 2 + int(jjSin((obj.var[2]*40) % 1023)*2);
						} else {
							if (obj.counter % 10 == 0) {
								obj.frameID++;
							}
							if (obj.frameID >= 4) {
								obj.frameID = 0;
							}
							brightness = 0;
						}
						jjDrawSpriteFromCurFrame(obj.xPos,obj.yPos,obj.curFrame,obj.direction,SPRITE::SINGLEHUE,teamColor + brightness,3);
						if (isPowerup(obj)) {
							int teamColor2 = determineTeamColor2(obj,creator);
							jjDrawSprite(obj.xPos, obj.yPos, weapon.determineSetID(),7,obj.frameID,obj.direction,SPRITE::SINGLEHUE,teamColor2 + brightness,3);
						}
					}
				} else {
					if (isPowerup(obj) && weapon.BouncyPU) obj.causesRicochet = true;
					jjDrawSpriteFromCurFrame(obj.xPos + jjCos((obj.justHit*400) % 1023)*3,obj.yPos,obj.curFrame,obj.direction,SPRITE::BRIGHTNESS,255,3);
					if (jjGameState != GAME::PAUSED) obj.justHit--;
				}
			} else if (obj.state == STATE::EXPLODE) {
				if (obj.var[1] == 0) {
					weapon.resortList(obj.creatorID,obj.var[0]);
					Webs[obj.creatorID].removeAt(obj.var[0]);
					obj.var[1] = 1;
				}
					obj.counter = 0;
					obj.lightType = 0;
					obj.frameID = 0;
					obj.lightType = 0;
					obj.justHit = 0;
					obj.determineCurAnim(weapon.determineSetID(),!isPowerup(obj)? 8 : 9);
					uint teamColor = determineTeamColor(obj,creator);
					if (teamColor != 0) {
						jjDrawSpriteFromCurFrame(obj.xPos,obj.yPos,obj.curFrame,obj.direction,SPRITE::SINGLEHUE,teamColor);
						
						if (isPowerup(obj)) {
							int teamColor2 = determineTeamColor2(obj,creator);
							jjDrawSprite(obj.xPos, obj.yPos, weapon.determineSetID(),7,obj.frameID,obj.direction,SPRITE::SINGLEHUE,teamColor2,3);
						}
					} else {
						jjDrawSpriteFromCurFrame(obj.xPos,obj.yPos,obj.curFrame,obj.direction,SPRITE::BRIGHTNESS,175,3);
					}
				obj.state = STATE::DONE;
				//obj.behavior = BEHAVIOR::EXPLOSION2;
				
			} else if (obj.state == STATE::DONE) {
				if (obj.var[1] == 0) {
					weapon.resortList(obj.creatorID,obj.var[0]);
					Webs[obj.creatorID].removeAt(obj.var[0]);
					obj.var[1] = 1;
				}
					
					
					uint teamColor = determineTeamColor(obj,creator);
					if (teamColor != 0) {
						jjDrawSpriteFromCurFrame(obj.xPos,obj.yPos,obj.curFrame,obj.direction,SPRITE::SINGLEHUE,teamColor);
						
						if (isPowerup(obj)) {
							int teamColor2 = determineTeamColor2(obj,creator);
							jjDrawSprite(obj.xPos, obj.yPos, weapon.determineSetID(),10,obj.frameID,obj.direction,SPRITE::SINGLEHUE,teamColor2,3);
						}
					} else {
						jjDrawSpriteFromCurFrame(obj.xPos,obj.yPos,obj.curFrame,obj.direction,SPRITE::BRIGHTNESS,175,3);
					}
					obj.counter++;
					if (obj.counter % 5 == 0) {
						obj.frameID++;
						
					}
					if (obj.frameID >= 4) {
						
						obj.state = STATE::DEACTIVATE;
					}
				
			}
			
			if (obj.state == STATE::DEACTIVATE) {
				if (obj.var[1] == 0) {
					weapon.resortList(obj.creatorID,obj.var[0]);
					Webs[obj.creatorID].removeAt(obj.var[0]);
					obj.var[1] = 1;
				}
				obj.delete();
			}
			
			obj.curFrame = jjAnimations[obj.curAnim].firstFrame + obj.frameID;
			if ((obj.state != STATE::EXPLODE && obj.state != STATE::DEACTIVATE && obj.state != STATE::DONE) &&
			(
			obj.counter >= int(obj.counterEnd*70) || 
			obj.yPos > jjWaterLevel || 
			!creator.isInGame || 
			(obj.var[5] != 0 && jjGameState == GAME::STARTED) || 
			(obj.var[5] != 2 && jjGameState == GAME::OVERTIME) ||
			obj.var[8] != weapon.determineTeam(obj,creator) ||
			limitDestroy()
			)) {
				obj.state = STATE::EXPLODE;
				
			}
			
		}
		bool limitDestroy() {
			if (Webs[obj.creatorID].length() > weapon.currentMaxWeb && weapon.MaxWeb != 0) {
				if (obj.var[0] < int(Webs[obj.creatorID].length() - weapon.currentMaxWeb)) {
					return true;
				}
			}
			return false;
		}
		
		bool onObjectHit(jjOBJ@ obj, jjOBJ@ playerBullet, jjPLAYER@ play, int force) {
			jjPLAYER@ creator = jjPlayers[obj.creatorID];
			if (play !is null) {
				if (obj.doesCollide(play)) {
					if (obj.state == STATE::FLY) {
						if ((MLLEWeapons::HelpfulBulletFunctions::PlayerIsEnemy(obj,play) || obj.creatorType != CREATOR::PLAYER) && play.blink == 0) {
							obj.frameID = 4;
						}
					}
					if (obj.state == STATE::WAIT && jjGameState != GAME::PREGAME) {
						if (((creator.blink == 0) || obj.creatorType != CREATOR::PLAYER)) {
							if (determineTargets(obj,play) && play.blink == 0) {
								if (weapon.EnhancedAirJump & 2 == 2) {
										if (play.helicopter > 0) {
											play.ySpeed = -1;
										}
										play.helicopterElapsed = 0;
										if (play.ySpeed > 0) {
											play.doubleJumpCount = 0;
										}
								}
								play.buttstomp = 121;
								if (isPowerup(obj) && (abs(play.xSpeed) > 10) && weapon.BouncyPU) {
									int targetDirection = play.xSpeed < 0? 1 : -1;
									play.spring(10 * targetDirection,0,true,false);
									if (jjGameTicks - weapon.lastTimeSinceSoundPlayed > 10) {
										jjSample(obj.xPos, obj.yPos, weapon.determineSample(2),64,40000 + (jjRandom() % 8000));
										weapon.lastTimeSinceSoundPlayed = jjGameTicks;
									}
								} else {
									if (play.xSpeed != 0) {
										play.xSpeed *= 0.5;
									}
									if (play.ySpeed != 0) {
										play.ySpeed *= 0.5;
									}
								}
							} else {
								if (weapon.EnhancedAirJump & 1 == 1) {
									
										if (play.helicopter > 0) {
											play.ySpeed = -1;
										}
										
										play.helicopterElapsed = 0;
										if (play.ySpeed > 0) {
											play.doubleJumpCount = 0;
										}
								}
							}
						}
					}
				}
			}
			if (obj.state == STATE::WAIT) {
				
				if (playerBullet !is null) {
					if (obj.justHit == 0) {
						if (jjGameState != GAME::PAUSED) {
							jjPLAYER@ targetCreator = jjPlayers[playerBullet.creatorID];
							if (playerBullet.creatorType != CREATOR::PLAYER || determineTargets(obj,targetCreator)) {
								if  (targetCreator.blink == 0 || playerBullet.creatorType != CREATOR::PLAYER) {
									int damage = isPowerup(obj)? 10 : 5;
									obj.counter += (70*damage);
									obj.justHit = 40;
									/*if (jjGameTicks - weapon.lastTimeSinceSoundPlayed > 10) {
										jjSample(obj.xPos, obj.yPos, weapon.determineSample(3 + (jjRandom() % 2)),64,41000 + (jjRandom() % 8000));//41000
										weapon.lastTimeSinceSoundPlayed = jjGameTicks;
									}*/
								}
								if ((playerBullet.creatorType != CREATOR::PLAYER || creator.blink == 0) && isPowerup(obj) && weapon.BouncyPU) {
									int lastRicochet = playerBullet.var[10];
									
									playerBullet.var[10] = 9;
									playerBullet.ricochet();
									playerBullet.var[10] = lastRicochet;
								}
							}
						}	
					}
				}
			}
			return true;
		}
		
		
		
		bool determineTargets(const jjOBJ@ obj, const jjPLAYER@ other) {
			if (obj.creatorType != CREATOR::PLAYER) return true;
			else if (weapon.SelfEntrap && obj.var[2] > 70*3 && jjPlayers[obj.creatorID] is other) return true;
			else return jjPlayers[obj.creatorID].isEnemy(other);
		}
		
		uint determineTeamColor(jjOBJ@ obj,jjPLAYER@ play) {
			if (obj.creatorType != CREATOR::PLAYER) return 0;
			array<uint> colors = {32,24,16,40,72,48,80};
			if (play.isJailed) return colors[4];
			if (jjGameMode == GAME::CTF) {
				if (play.team < 4) return colors[play.team];
				else return colors[4];
			}
			if (jjGameCustom == GAME::RT) {
				if (play is jjBottomFeeder) return colors[5];
				if (play is jjTokenOwner) return colors[2];
			}
			if (play.isZombie) return colors[6];
			
			
			return 0;
		}
		uint determineTeamColor2(jjOBJ@ obj,jjPLAYER@ play) {
			if (obj.creatorType != CREATOR::PLAYER) return 0;
			array<uint> colors = {88,56,88,32,64,24};
			if (play.isJailed) return colors[4];
			if (jjGameMode == GAME::CTF) {
				if (play.team < 4) return colors[play.team];
				else return colors[4];
			}
			if (jjGameCustom == GAME::RT) {
				if (play is jjBottomFeeder) return colors[3];
				if (play is jjTokenOwner) {
				
					uint result = 16;
					const int time = 10;
					if (obj.counter > time) {
						uint color = uint(obj.counter / time) % 8;
						result = 16 + (8*color);
					}
					return result;
				}
			}
			if (play.isZombie) return colors[5];
			
			
			return 0;
		}
		
	}
}