UNPKG

node-haxball

Version:

The most powerful and lightweight API that allows you to develop your original Haxball(www.haxball.com) host, client, and standalone applications both on node.js and browser environments and also includes every possible hack and functionality that you can

257 lines (243 loc) 7.87 kB
module.exports = function (API) { const { OperationType, VariableType, ConnectionState, AllowFlags, Direction, CollisionFlags, CameraFollow, BackgroundType, GamePlayState, Callback, Utils, Room, Replay, Query, Library, RoomConfig, Plugin, Renderer, Errors, Language, Impl } = API; Object.setPrototypeOf(this, Plugin.prototype); Plugin.call(this, "japaneseSoccer", true, { version: "0.1", author: "abc", description: `This plugin sets up a japanese soccer game.`, allowFlags: AllowFlags.CreateRoom }); this.defineVariable({ name: "goalSize", type: VariableType.Integer, value: 100, range: { min: 10, max: 500, step: 1 }, description: "Length of each goal line in map units." }); this.defineVariable({ name: "goalsPerPlayer", type: VariableType.Integer, value: 5, range: { min: 1, max: Infinity, step: 1 }, description: "Number of goals needed to concede in order to knock out a player." }); var that = this, gameState = null, goalConcederPlayerId = null, auto = false; function arrangePlayers(kickOffPlayerId){ var {goals, discs, playerPhysics} = that.room.stadium; Object.keys(gameState).forEach((pid)=>{ pid = parseInt(pid); if (kickOffPlayerId==pid){ var a = 2*gameState[pid].goalId*Math.PI/that.room.players.filter((x)=>(x.team.id==1)).length, kickOffDist = 10+playerPhysics.radius+discs[0].radius; that.room.setPlayerDiscProperties(pid, { x: kickOffDist*Math.cos(a), y: kickOffDist*Math.sin(a) }); } else{ var {p0, p1} = goals[gameState[pid].goalId]; that.room.setPlayerDiscProperties(pid, { x: (p0.x+p1.x)/2, y: (p0.y+p1.y)/2 }); } }); } function refreshStadium(numberOfPlayers){ var angleInc = Math.PI/numberOfPlayers, r = that.goalSize/(2*Math.sin(angleInc/2)), mapSize = r + 100; var stadiumJson = { "name": "Japanese Soccer v"+numberOfPlayers, "width": mapSize, "height": mapSize, "spawnDistance": 50, "bg": { "type": "none", "width": mapSize, "height": mapSize, "kickOffRadius": 0, "cornerRadius": 0, "borderRadius": 0, "color": "484848" }, "cameraWidth": 0, "cameraHeight": 0, "maxViewWidth": 0, "cameraFollow": "ball", "canBeStored": true, "kickOffReset": "partial", "playerPhysics": { "radius": 15, "bCoef": 1.0e-323, "invMass": 0.5, "damping": 0.96, "cGroup": ["red","blue"], "acceleration": 0.11, "gravity": [0,0], "kickingAcceleration": 0.083, "kickingDamping": 0.96, "kickStrength": 4.545, "kickback": 0 }, "ballPhysics": { "radius": 5.8, "bCoef": 0.474, "cMask": ["all"], "damping": 0.99, "invMass": 1.5, "gravity": [0,0], "color": "FFCC00", "cGroup": ["ball"] }, "traits": { "goalPost": { "radius": 8, "invMass": 0, "bCoef": 0.5, "color": "252525" }, "goalNet": { "vis": true, "bCoef": 0.1, "cMask": ["ball"], "color": "003333" } }, "redSpawnPoints": [], "blueSpawnPoints": [], "vertexes": [], "segments": [], "goals": [], "discs": [], "planes": [], "joints": [], }; var angle = -angleInc/2; stadiumJson.vertexes.push({"x": r*Math.cos(angle), "y": r*Math.sin(angle)}); for (var i=0;i<2*numberOfPlayers;i++){ angle+=angleInc; stadiumJson.vertexes.push({"x": r*Math.cos(angle), "y": r*Math.sin(angle)}); if (i%2==0){ var p0 = [stadiumJson.vertexes[i].x, stadiumJson.vertexes[i].y], p1 = [stadiumJson.vertexes[i+1].x, stadiumJson.vertexes[i+1].y]; stadiumJson.segments.push({"v0": i, "v1": i+1, "curve": 178, "trait": "goalNet"}); stadiumJson.discs.push({"pos": p0, "trait": "goalPost"}); stadiumJson.discs.push({"pos": p1, "trait": "goalPost"}); stadiumJson.goals.push({"p0": p0, "p1": p1, team: "red"}); //stadiumJson.redSpawnPoints.push([(p0[0]+p1[0])/2, (p0[1]+p1[1])/2]); } else stadiumJson.segments.push({"v0": i, "v1": i+1}); } auto = true; that.room.stopGame(); that.room.setScoreLimit(0); that.room.setTimeLimit(0); that.room.setCurrentStadium(Utils.parseStadium(JSON.stringify(stadiumJson))); that.room.startGame(); auto = false; } function knockOutPlayer(id){ that.room.setPlayerTeam(id, 2); var players = that.room.players.filter((x)=>(x.team.id==1)); var numberOfPlayers = players.length; if (numberOfPlayers<2){ var { id, name } = players[0]; that.room.sendAnnouncement("Japanese soccer was won by ["+id+"]"+name+" with "+gameState[id].score+" points remaining.", null, 0xff0000); auto = true; that.room.stopGame(); auto = false; gameState = null; goalConcederPlayerId = null; return; } refreshStadium(numberOfPlayers); arrangePlayers(); } function restart(){ var players = that.room.players.filter((x)=>(x.team.id==1)); var numberOfPlayers = players.length; if (numberOfPlayers<2){ that.room.sendAnnouncement("Cannot start japanese soccer with less than 2 players. Move players to red team and restart...", null, 0xff0000); return; } var pids = []; players.forEach((x)=>(Math.random()<0.5)?pids.push(x.id):pids.unshift(x.id)); goalConcederPlayerId = null; gameState = pids.reduce((val, id, idx)=>{ val[id] = { score: that.goalsPerPlayer, goalId: idx }; return val; }, {}); pids.forEach((id)=>that.room.setPlayerAvatar(id, ""+that.goalsPerPlayer, true)); refreshStadium(numberOfPlayers); arrangePlayers(); } this.onGameStart = (byId)=>{ if (auto || gameState) return; Utils.runAfterGameTick(restart); }; this.onGameStop = (byId)=>{ if (auto || !gameState) return; gameState = null; goalConcederPlayerId = null; that.room.sendAnnouncement("Japanese soccer aborted.", null, 0xff0000); }; this.onTeamGoal = (teamId, goalId, goalObj, discId, discObj)=>{ if (!gameState) return; var id = parseInt(Object.keys(gameState).find((id)=>(gameState[id].goalId==goalId))); if (isNaN(id)) return; var s = gameState[id].score; gameState[id].score = --s; Utils.runAfterGameTick(()=>{ that.room.setPlayerAvatar(id, ""+s, true); }); goalConcederPlayerId = id; }; this.onPositionsReset = ()=>{ if (!gameState || goalConcederPlayerId==null) return; Utils.runAfterGameTick(()=>{ if (gameState[goalConcederPlayerId].score<=0) knockOutPlayer(goalConcederPlayerId); else arrangePlayers(goalConcederPlayerId); goalConcederPlayerId = null; }); }; this.onPlayerLeave = (id)=>{ if (!gameState?.[id]) return; goalConcederPlayerId = null; Utils.runAfterGameTick(()=>{ knockOutPlayer(); }); }; /* this.onPlayerTeamChange = (id, teamId, byId)=>{ if (gameState || teamId!=1) return; Utils.runAfterGameTick(restart); }; */ this.initialize = ()=>{ gameState = null; goalConcederPlayerId = null; //Utils.runAfterGameTick(restart); }; this.finalize = ()=>{ gameState = null; goalConcederPlayerId = null; }; }