Home Reference Source

src/server/utils/ondamage.js

import { GLOBAL } from '../../client/js/global'
import { getField, setField, incrementField } from '../server'
import { getTeamNumber, smartEmit } from './serverutils'
import { tmpdir } from 'os'
import { spawnAtom } from './atoms'

/**
 * ondamage.js
 * Contains functions:
 *  - damage() Runs when a player gets damaged. Updates scores and checks if a player has been killed.
 *  - splash() Runs when a collision needs to cause splash damage. Creates explosion effect and deals extra damage.
 */

/**
 * Changes the health of the player by the amount given.
 * @param {*} data The data sent by the client. Contains:
 *  - damage (number)
 *  - player (id string of player that was hit)
 *  - id (id string of compound)
 *  - sentBy (id string of player that sent compound)
 * @param {string} room This room.
 * @param {*} socket This socket.
 * Must include the player id and amount to damage.
 * Amount may be negative (for health boost).
 */
export function damage (data, room, socket) {
	let thisRoom = getField(['rooms', room])
	let thisPlayer = thisRoom.players[data.player]

	if (thisPlayer !== undefined) {
		// thisPlayer.health -= data.damage;
		if (data.damage > thisPlayer.shield) {
			setField(thisPlayer.health - data.damage + thisPlayer.shield, ['rooms', room, 'players', data.player, 'health'])
			// Send damage indicator data
			smartEmit(socket, room, 'serverSendDamageIndicator', {
				damage: data.damage - thisPlayer.shield,
				posX: thisPlayer.posX,
				posY: thisPlayer.posY
			})
		}
		else {
			smartEmit(socket, room, 'serverSendDamageIndicator', {
				damage: data.damage - thisPlayer.shield,
				posX: thisPlayer.posX,
				posY: thisPlayer.posY
			})
		}

		// Add damage to database
		if (thisPlayer.damagedBy[data.sentBy] === undefined) {
			setField(0, ['rooms', room, 'players', data.player, 'damagedBy', data.sentBy])
		}
		// thisPlayer.damagedBy[data.sentBy] += data.damage;
		setField(thisPlayer.damagedBy[data.sentBy] + data.damage, ['rooms', room, 'players', data.player, 'damagedBy', data.sentBy])

		// Check if the player has died.
		if (thisPlayer.health <= 0) {
			// console.log(thisRoom.teams.indexOf(socket.handshake.query.team));

			// Releases atoms and deletes the entire atoms array in player
			for (let at in thisPlayer.atomList) {
				for (let i = 0; i < GLOBAL.MAX_DEATH_ATOMS && i < thisPlayer.atomList[at]; i++) {
					spawnAtom(thisPlayer.posX, thisPlayer.posY, at, room, 'all', false)
				}
			}
			for (let at in thisPlayer.atomList) {
				setField(0, ['rooms', room, 'players', data.player, 'atomList', at])
			}

			// Set defense to 0
			setField(0, ['rooms', room, 'players', data.player, 'shield'])

			// Reset position to spawnpoint
			setField(GLOBAL.SPAWN_POINTS[getTeamNumber(room, thisPlayer.team)].x * GLOBAL.GRID_SPACING * 2, ['rooms', room, 'players', data.player, 'posX'])
			setField(GLOBAL.SPAWN_POINTS[getTeamNumber(room, thisPlayer.team)].y * GLOBAL.GRID_SPACING * 2, ['rooms', room, 'players', data.player, 'posY'])
			setField(GLOBAL.MAX_HEALTH, ['rooms', room, 'players', data.player, 'health'])
			setField(true, ['rooms', room, 'players', data.player, 'dead']) // This will be reset when it has been verified that the player has been placed at the proper spawnpoint

			// Send player death info to client only if the player being checked is equal to the player dying
			let pl = getField(['rooms', room, 'players', data.player])

			smartEmit(socket, room, 'serverSendPlayerDeath', { posX: pl.posX, posY: pl.posY, vx: pl.vx, vy: pl.vy }, data.player)

			// Announce death. TODO make some cool messages
			smartEmit(socket, room, 'serverAnnouncement', {
				message: pl.name + ' was obliterated by ' + getField(['rooms', room, 'players', data.sentBy, 'name']),
				sendingTeam: pl.team
			})

			// Check if the nucleus has died
			if (getField(['rooms', room, 'tiles', 'n' + getTeamNumber(room, pl.team), 'captured'])) {
				// Announce final death
				smartEmit(socket, room, 'serverAnnouncement', {
					message: 'FINAL KILL!!!',
					sendingTeam: pl.team
				})

				setField(true, ['rooms', room, 'players', data.player, 'spectating'])
			}

			// Check if a team was eliminated
			if (data.id !== undefined) {
				for (let team of getField(['rooms', room, 'teams'])) {
					// console.log(team)
					if (!team.dead) {
						let stillAlive = false
						for (let player of team.players) {
							if (!getField(['rooms', room, 'players', player, 'spectating'])) {
								stillAlive = true
							}
						}
						if (!stillAlive) {
							// Announce elimination of team
							team.dead = true
							smartEmit(socket, room, 'serverAnnouncement', {
								message: team.name + ' has been eliminated!',
								sendingTeam: team.name
							})

							// Check if a team has won
							let deadCount = 0
							let notDeadTeam = null
							for (let team of getField(['rooms', room, 'teams'])) {
								if (team.dead) {
									deadCount++
								}
								else {
									notDeadTeam = team.name
								}
							}

							console.log(deadCount)
							console.log(notDeadTeam)

							// A team has won!
							if (deadCount === getField(['rooms', room, 'teams']).length - 1) {
								let dataToSend = {
									winner: notDeadTeam
									// teamScore: thisRoom.teams[dataToSend.teamSlot].score
									// other data here TODO post ranking
								}
								smartEmit(socket, room, 'serverSendWinner', dataToSend)
							}
						}
					}
				}
			}
			// // Award points (TODO)_
			// if (data.id !== undefined) {
			// 	// Read damagedBy to award points, clear in the process
			// 	let max = null
			// 	let dataToSend
			// 	for (let pl in thisPlayer.damagedBy) {
			// 		dataToSend = {
			// 			player: pl,
			// 			teamSlot: getTeamNumber(room, thisRoom.compounds[data.id].sendingTeam),
			// 			increment: GLOBAL.ASSIST_SCORE,
			// 			kill: false
			// 		}

			// 		// Add to team score, checking if team score is initialized
			// 		setField((thisRoom.teams[dataToSend.teamSlot].score === undefined) ? dataToSend.increment : thisRoom.teams[dataToSend.teamSlot].score + dataToSend.increment, ['rooms', room, 'teams', dataToSend.teamSlot, 'score'])

			// 		socket.to(room).broadcast.emit('serverSendScoreUpdate', dataToSend)
			// 		socket.emit('serverSendScoreUpdate', dataToSend)
			// 		if (max === null || thisPlayer.damagedBy[pl] > thisPlayer.damagedBy[max]) {
			// 			max = pl
			// 		}
			// 	}

			// 	// Add to score of person who dealt the most damage
			// 	dataToSend.player = max
			// 	dataToSend.increment = GLOBAL.KILL_SCORE - GLOBAL.ASSIST_SCORE
			// 	dataToSend.kill = true
			// 	socket.to(room).broadcast.emit('serverSendScoreUpdate', dataToSend)
			// 	socket.emit('serverSendScoreUpdate', dataToSend)

			// 	// Add to team score
			// 	incrementField(dataToSend.increment, ['rooms', room, 'teams', dataToSend.teamSlot, 'score'])

			// 	// Clear damagedBy values
			// 	for (let pl in thisPlayer.damagedBy) {
			// 		setField(0, ['rooms', room, 'players', data.player, 'damagedBy', pl])
			// 	}

			// 	// Check if a team won
			// 	let highScores = [] // Possible winning teams
			// 	let maxScore = 0
			// 	for (let tm of thisRoom.teams) {
			// 		if (tm.score >= GLOBAL.WINNING_SCORE) {
			// 			highScores.push(tm)
			// 			if (maxScore < tm.score) {
			// 				maxScore = tm.score
			// 			}
			// 		}
			// 	}
			// 	for (let winningTm of highScores) {
			// 		if (winningTm.score === maxScore) {
			// 			let dataToSend = {
			// 				winner: winningTm
			// 				// teamScore: thisRoom.teams[dataToSend.teamSlot].score
			// 				// other data here TODO post ranking
			// 			}
			// 			socket.to(room).broadcast.emit('serverSendWinner', dataToSend)
			// 			socket.emit('serverSendWinner', dataToSend)

			// 			// Close room after delay (kick all players)
			// 			setTimeout(() => {
			// 				socket.emit('serverSendDisconnect', {})
			// 				socket.to(room).broadcast.emit('serverSendDisconnect', {})
			// 			}, GLOBAL.ROOM_DELETE_DELAY)
			// 		}
			// 	}
			// }
		}
	}
	else {
		console.warn('Player of ID ' + data.player + ' couldn\'t be damaged because they don\'t exist!')
	}
}

export function damageTile (tileID, damageAmount, player, room, socket) {
	incrementField(-damageAmount, ['rooms', room, 'tiles', tileID, 'health'])

	// console.log('tile ' + tileID + ' is now at ' + getField(['rooms', room, 'tiles', tileID, 'health']))
	let hpData = {
		newHealth: getField(['rooms', room, 'tiles', tileID, 'health']),
		tileX: getField(['rooms', room, 'tiles', tileID, 'globalX']),
		tileY: getField(['rooms', room, 'tiles', tileID, 'globalY'])
	}

	smartEmit(socket, room, 'serverSendTileHealth', hpData)

	// Check if tile is fully captured
	if (getField(['rooms', room, 'tiles', tileID, 'health']) <= 0) {
		for (let i = 0; i < 3; i++) {
			if (getField(['rooms', room, 'teams', i]).name === getField(['rooms', room, 'players', player, 'team'])) {
				// Notify clients of texture change
				let data = {
					teamNumber: i,
					tileX: getField(['rooms', room, 'tiles', tileID, 'globalX']),
					tileY: getField(['rooms', room, 'tiles', tileID, 'globalY'])
				}
				smartEmit(socket, room, 'serverSendTileCapture', data)
				let tileCaptureMSG = {
					message: 'A ' + getField(['rooms', room, 'tiles', tileID, 'type']) + ' has been captured by ' + getField(['rooms', room, 'players', player, 'name']),
					sendingTeam: getField(['rooms', room, 'players', player, 'team'])
				}
				smartEmit(socket, room, 'serverAnnouncement', tileCaptureMSG)

				// Set capture status
				setField(true, ['rooms', room, 'tiles', tileID, 'captured'])
				setField(getField(['rooms', room, 'players', player, 'team']), ['rooms', room, 'tiles', tileID, 'owner'])

				// Distribute points
				incrementField(GLOBAL.CAPTURE_SCORE, ['rooms', room, 'teams', i, 'score'])

				// Reset health
				setField(GLOBAL[('MAX_' + getField(['rooms', room, 'tiles', tileID, 'type']) + '_HEALTH').toUpperCase()], ['rooms', room, 'tiles', tileID, 'health'])
				let hpData = {
					newHealth: getField(['rooms', room, 'tiles', tileID, 'health']),
					tileX: getField(['rooms', room, 'tiles', tileID, 'globalX']),
					tileY: getField(['rooms', room, 'tiles', tileID, 'globalY'])
				}
				smartEmit(socket, room, 'serverSendTileHealth', hpData)
				return true
			}
		}
	}
}

/**
 * TODO
 */
export function splash () {

}