Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Teleportation mutator | ak-47 | Mutator | 10 |
#pragma name "Teleportations (by ak-47)"
namespace COMMAND {
const string PREFIX = "[~!@\\.;]";
const string POS = "pos(pix)?";
const string FLY = "fly ?(\\w+)?";
const string TP = "tp ?(\\d\\d?)";
const string TP_HERE = "tphere ?(\\d\\d?)";
const string TP_XY = "tp ?(\\d*)[.,] ?(\\d*)";
const string TP_SETTINGS = "tp(settings|confi?g?)";
const string SAVE_SETTINGS = "tpsave(settings|confi?g?)? ?(.*)";
const string LOAD_SETTINGS = "tpload(settings|confi?g?)? ?(.*)";
const string TAKEOVER = "takeover ?(\\d\\d?) ?(lax)?";
const string RELEASE = "release";
const string WARP_EFFECT = "warp(effect)? ?(\\w+)?";
const string MOUSE_CAMERA = "m(ouse)?cam(era)? ?(.*)";
const string CONTROLS = "controls ?(\\w+)?";
const string FROZEN = "frozen ?(\\w+)?";
const string FREEZE = "freeze";
const string UNFREEZE = "unfreeze";
}
namespace CONFIG {
const uint MAX_LINES = 10;
const string FILE_NAME = "tpconfig.asdat";
const string LINE_PATTERN = "(\\w+)=(.*)";
namespace OPTION {
const string FLY = "fly";
const string WARP_EFFECT = "useWarpEffect";
const string CONTROLS = "unlockControls";
const string MOUSE_CAMERA = "mouseCamera";
}
}
namespace KEY {
const int8 MOUSE_CAMERA = 0x02; // VK_RBUTTON
const int8 MOUSE_TRACK = 0x02; // VK_RBUTTON
const int8 TAKEOVER = 0x10; // VK_SHIFT
}
const uint PRECISION_FRAME_THRESHOLD = 10;
const int8 NO_PLAYER_INFORMATION = -1;
const int FRAME_PIXELS = 32;
int8 takenOverPlayerID = 0;
bool laxTakeOver = false;
bool fly = false;
bool useWarpEffect = true;
bool frozen = false;
bool mouseCamera = true;
// Mouse and arrow camera, inspired by the "look around" feature
// introduced in Universal Test Manager (v1.3) by Gigo
bool usingMouseCamera = false;
bool unlockControls = false;
void enableMouseCamera() { usingMouseCamera = true; }
void disableSpecialCamera() { usingMouseCamera = false; }
void performMouseCamera(jjPLAYER@ player) {
// middleTextTimer = 0;
float posX = float(jjMouseX - 0.5 * jjResolutionWidth) / float(0.5 * jjResolutionWidth);
float posY = float(jjMouseY - 0.5 * jjResolutionHeight) / float(0.5 * jjResolutionHeight);
if (posX < -1) posX = -1;
if (posX > 1) posX = 1;
if (posY < -1) posY = -1;
if (posY > 1) posY = 1;
player.cameraFreeze(
player.xPos + 1000 * posX,
player.yPos + 1000 * posY,
true, false
);
if (!jjKey[KEY::MOUSE_CAMERA]) {
for (int8 i = 0; i < jjLocalPlayerCount; i++) {
jjLocalPlayers[i].cameraUnfreeze(true);
}
usingMouseCamera = false;
}
}
void manageControls(jjPLAYER@ player) {
if (!unlockControls) {
player.keyLeft = false;
player.keyRight = false;
player.keyUp = false;
player.keyDown = false;
player.keySelect = false;
player.keyRun = false;
player.keyJump = false;
player.keyFire = false;
}
}
void onPlayer(jjPLAYER@ player) {
player.freeze(frozen);
if (usingMouseCamera) {
manageControls(player);
performMouseCamera(player);
}
}
enum PACKET_ID {UPDATE_POSITION, TAKEOVER}
void onLevelLoad() {
loadSettings(CONFIG::FILE_NAME, false);
}
bool loadSettings(const string fileName = CONFIG::FILE_NAME, bool log = true)
{
jjSTREAM settingsFile (fileName);
array<string> lines;
if (settingsFile.isEmpty()) {
saveSettings(fileName);
}
while (!settingsFile.isEmpty())
{
string nextLine;
if (lines.length() == CONFIG::MAX_LINES)
{
if (log) jjAlert("|>> Error: " + fileName + " configuration file is corrupted. Try to reset it with !tpsave.");
return false;
}
settingsFile.getLine(nextLine);
lines.insertLast(nextLine);
}
uint currentLineID = 0;
string currentLine = "";
string currentKey = "(unknown)";
string currentValue = "(unknown)";
for (currentLineID; currentLineID < lines.length(); ++currentLineID)
{
string currentHeader = "|>> " + fileName + ", line " + formatUInt(currentLineID + 1) + ":";
currentLine = lines[currentLineID];
array<string> data;
if (jjRegexMatch(currentLine, CONFIG::LINE_PATTERN, data)) {
currentKey = data[1];
currentValue = data[2];
currentHeader = "|>> " + fileName + ", line " + formatUInt(currentLineID + 1) + ", option " + currentKey + ":";
}
else {
if (log) {
jjAlert(currentHeader);
jjAlert("|>> Error: configuration format is invalid! Try to reset with !tpsave.");
}
return false;
}
string boolCastErrorMsg = currentHeader + " expected either 'on' or 'off'";
if (jjRegexMatch(currentKey, CONFIG::OPTION::FLY, true))
parseBool(fly, currentValue, bool(fly), boolCastErrorMsg, log);
else if (jjRegexMatch(currentKey, CONFIG::OPTION::WARP_EFFECT, true))
parseBool(useWarpEffect, currentValue, bool(useWarpEffect), boolCastErrorMsg, log);
else if (jjRegexMatch(currentKey, CONFIG::OPTION::CONTROLS, true))
parseBool(unlockControls, currentValue, bool(unlockControls), boolCastErrorMsg, log);
else if (jjRegexMatch(currentKey, CONFIG::OPTION::MOUSE_CAMERA, true))
parseBool(mouseCamera, currentValue, bool(mouseCamera), boolCastErrorMsg, log);
else {
if (log) {
jjAlert(currentHeader);
jjAlert("|>> Error: unexpected option " + currentKey + ". Try to reset with !tpsave.");
}
return false;
}
}
return true;
}
bool saveSettings(const string fileName = CONFIG::FILE_NAME)
{
jjSTREAM settingsFile;
settingsFile.write(CONFIG::OPTION::FLY + "=" + (fly ? "on" : "off") + "\n");
settingsFile.write(CONFIG::OPTION::WARP_EFFECT + "=" + (useWarpEffect ? "on": "off") + "\n");
settingsFile.write(CONFIG::OPTION::CONTROLS + "=" + (unlockControls ? "on": "off") + "\n");
settingsFile.write(CONFIG::OPTION::CONTROLS + "=" + (unlockControls ? "on": "off") + "\n");
return settingsFile.save(fileName);
}
void onReceive(jjSTREAM &in packet, int fromClientID)
{
int8 packetID;
packet.pop(packetID);
switch (packetID)
{
case UPDATE_POSITION:
onUpdatePositionPacket(packet, fromClientID);
break;
case TAKEOVER:
onTakeoverPacket(packet, fromClientID);
break;
}
}
void onPlayerInput(jjPLAYER@ player)
{
if (mouseCamera && jjKey[KEY::MOUSE_CAMERA])
usingMouseCamera = true;
if (jjIsServer) {
jjPLAYER@ targetPlayer = jjKey[KEY::TAKEOVER] ? jjPlayers[takenOverPlayerID] : player;
followLocalPlayerMouse(targetPlayer, player);
}
else if (laxTakeOver ? true : player.playerID != takenOverPlayerID)
followLocalPlayerMouse(player, player);
}
bool parseBool(
bool &out boolRef,
const string argument,
bool defaultValue = true,
const string errorAlertMessage = "|>> Error: Invalid parameter - use either 'on' or 'off'",
bool log = true
)
{
if (argument != "")
if (jjRegexMatch(argument, "(y(es)?|on|1|true)", true))
boolRef = true;
else if (jjRegexMatch(argument, "(no?|off|0|false)", true))
boolRef = false;
else
{
if (log) jjAlert(errorAlertMessage);
return false;
}
else boolRef = defaultValue;
return true;
}
bool isCommand(const string commandString, const string commandPattern, bool caseSensitive = false)
{
return jjRegexMatch(commandString, COMMAND::PREFIX + commandPattern, !caseSensitive);
}
bool isCommand(const string commandString, const string commandPattern, array<string> &out paramCollector, bool caseSensitive = false)
{
return jjRegexMatch(commandString, COMMAND::PREFIX + commandPattern, paramCollector, !caseSensitive);
}
void printFly() {
jjConsole("Smooth mouse flying: " + (fly ? "||ON" : "|OFF"), true);
}
void printWarpEffect() {
jjConsole("Warp effect: " + (useWarpEffect ? "||ON" : "|OFF"), true);
}
void printUnlockControls() {
jjConsole("Unlock controls in mouse camera mode: " + (unlockControls ? "||ON" : "|OFF"), true);
}
void printMouseCamera() {
jjConsole("Auto mouse camera mode: " + (mouseCamera ? "||ON" : "|OFF"), true);
}
void printSettings() {
printFly();
printWarpEffect();
printUnlockControls();
printMouseCamera();
}
bool onLocalChat(string &in stringReceived, CHAT::Type chatType)
{
jjPLAYER@ player = jjLocalPlayers[0];
array<string> posArgument;
if (isCommand(stringReceived, COMMAND::POS, posArgument))
{
string xPos, yPos;
if (posArgument[1] == "")
{
xPos = formatUInt(int(player.xPos / FRAME_PIXELS));
yPos = formatUInt(int(player.yPos / FRAME_PIXELS));
}
else
{
xPos = formatUInt(int(player.xPos));
yPos = formatUInt(int(player.yPos));
}
jjConsole("Your position is: ||" + xPos + ", " + yPos, true);
return true;
}
array<string> flyArgument;
if (isCommand(stringReceived, COMMAND::FLY, flyArgument))
{
const string argument = flyArgument[1];
if (argument != "")
parseBool(fly, argument, bool(fly));
printFly();
return true;
}
array<string> useWarpEffectArgument;
if (isCommand(stringReceived, COMMAND::WARP_EFFECT, useWarpEffectArgument))
{
const string argument = useWarpEffectArgument[2];
if (argument != "")
parseBool(useWarpEffect, argument, bool(useWarpEffect));
printWarpEffect();
return true;
}
array<string> unlockControlsArgument;
if (isCommand(stringReceived, COMMAND::CONTROLS, unlockControlsArgument))
{
const string argument = unlockControlsArgument[1];
if (argument != "")
parseBool(unlockControls, argument, bool(unlockControls));
printUnlockControls();
return true;
}
if (isCommand(stringReceived, COMMAND::TP_SETTINGS)) {
jjAlert(">> Current teleportation settings:");
printSettings();
return true;
}
array<string> loadSettingsArgument;
if (isCommand(stringReceived, COMMAND::LOAD_SETTINGS, loadSettingsArgument))
{
string settingsFileName = loadSettingsArgument[2];
settingsFileName = (settingsFileName != "") ? settingsFileName : CONFIG::FILE_NAME;
bool loaded = loadSettings(settingsFileName);
if (loaded) {
jjAlert(">> Loaded settings from " + settingsFileName);
printSettings();
}
return true;
}
array<string> saveSettingsArgument;
if (isCommand(stringReceived, COMMAND::SAVE_SETTINGS, saveSettingsArgument))
{
string settingsFileName = saveSettingsArgument[2];
settingsFileName = (settingsFileName != "") ? settingsFileName : CONFIG::FILE_NAME;
bool saved = saveSettings(settingsFileName);
if (saved) {
jjAlert(">> Saved settings to " + settingsFileName);
printSettings();
}
return true;
}
array<string> mouseCameraArgument;
if (isCommand(stringReceived, COMMAND::MOUSE_CAMERA, mouseCameraArgument))
{
string argument = mouseCameraArgument[3];
if (argument != "")
parseBool(mouseCamera, argument, bool(mouseCamera));
printMouseCamera();
return true;
}
array<string> frozenArgument;
if (isCommand(stringReceived, COMMAND::FROZEN, frozenArgument))
{
string argument = frozenArgument[1];
parseBool(frozen, argument, false);
return true;
}
if (isCommand(stringReceived, COMMAND::FREEZE))
{
frozen = true;
return true;
}
if (isCommand(stringReceived, COMMAND::UNFREEZE))
{
frozen = false;
return true;
}
if (!jjIsServer)
return false;
array<string> takeoverArguments;
if (isCommand(stringReceived, COMMAND::TAKEOVER, takeoverArguments))
{
int8 candidate = saneGetPlayerID(uint8(parseUInt(takeoverArguments[1]) - 1));
bool lax = takeoverArguments[2] != "";
if (candidate != NO_PLAYER_INFORMATION)
{
setTakenOver(uint8(candidate), lax);
jjConsole(jjPlayers[takenOverPlayerID].nameUnformatted + " has been taken over. You've become Darth Vader!");
}
return true;
}
if (isCommand(stringReceived, COMMAND::RELEASE))
{
if (takenOverPlayerID != 0)
jjConsole(jjPlayers[takenOverPlayerID].nameUnformatted + " has been released.");
setTakenOver(0);
return true;
}
return false;
}
void onChat(int clientID, string &in stringReceived, CHAT::Type chatType)
{
if (!jjIsServer) return;
jjPLAYER@ player = jjPlayersWithClientID(clientID)[0];
array<string> tpXYArguments;
if (isCommand(stringReceived, COMMAND::TP_XY, tpXYArguments)) {
int xPos = int(parseInt(tpXYArguments[1]) * FRAME_PIXELS);
int yPos = int(parseInt(tpXYArguments[2]) * FRAME_PIXELS);
setPlayerPosition(player, xPos, yPos);
return;
}
jjPLAYER@ targetPlayer;
uint8 playerID = player.playerID;
array<string> tpPlayerArguments;
if (isCommand(stringReceived, COMMAND::TP, tpPlayerArguments))
{
uint8 targetPlayerID = parseUInt(tpPlayerArguments[1]) - 1;
@targetPlayer = @jjPlayers[targetPlayerID];
if (canTeleport(playerID, targetPlayerID))
setPlayerPosition(player, targetPlayer);
return;
}
array<string> tpHerePlayerArguments;
if (isCommand(stringReceived, COMMAND::TP_HERE, tpHerePlayerArguments))
{
uint8 targetPlayerID = parseUInt(tpHerePlayerArguments[1]) - 1;
@targetPlayer = @jjPlayers[targetPlayerID];
if (canTeleport(targetPlayerID, playerID))
setPlayerPosition(targetPlayer, player);
return;
}
}
/*
Moves a local player from the current position to the desired one,
determined by the arguments following the first.
Works only for local player.
*/
void setLocalPlayerPosition
(
jjPLAYER@ player,
int xPos,
int yPos,
bool affectDirection = true,
bool isTeleportationToPlayer = false
)
{
if (affectDirection && player.xPos != xPos)
player.direction = int((player.xPos - xPos) < 0 ? abs(player.direction) : -abs(player.direction));
if ((!fly || isTeleportationToPlayer) && useWarpEffect)
player.warpToTile(xPos / FRAME_PIXELS, yPos / FRAME_PIXELS);
else {
player.xPos = xPos;
player.yPos = yPos;
}
}
void setPlayerPosition
(
jjPLAYER@ player,
int xPos,
int yPos,
int8 toPlayerID = NO_PLAYER_INFORMATION,
bool log = true
)
{
setLocalPlayerPosition(player, xPos, yPos, true, toPlayerID != NO_PLAYER_INFORMATION);
if (log) logPlayerTeleportation(player, xPos, yPos, toPlayerID);
if (!player.isLocal && jjIsServer)
sendUpdatePositionPacket(player, xPos, yPos, toPlayerID, log);
}
void setPlayerPosition
(
jjPLAYER@ player,
jjPLAYER@ toPlayer,
bool log = true
)
{
setPlayerPosition(player, int(toPlayer.xPos), int(toPlayer.yPos), toPlayer.playerID, log);
}
int8 saneGetPlayerID(uint8 playerID, bool mustBeInGame = true, bool log = true)
{
if (playerID < 0 || playerID > 31)
{
if (log) jjConsole("|>> Player number in list must be in range 1-32", true);
return NO_PLAYER_INFORMATION;
};
if (mustBeInGame && !jjPlayers[playerID].isInGame)
{
if (log) jjConsole("|>> Player is not in the game", true);
return NO_PLAYER_INFORMATION;
}
return playerID;
}
bool canTeleport
(
uint8 playerID,
uint8 targetPlayerID,
bool log = true
)
{
if (targetPlayerID == playerID)
{
if (log) jjConsole("|>> Hold your horses, young lady", true);
return false;
}
jjPLAYER@ toPlayer = jjPlayers[saneGetPlayerID(targetPlayerID, true, log)];
return toPlayer.isInGame;
}
uint lastClickTime = 0;
void followLocalPlayerMouse(jjPLAYER@ targetPlayer, jjPLAYER@ mimickedPlayer)
{
if
(
KEY::MOUSE_TRACK != -1
&& mimickedPlayer.isLocal
&& targetPlayer.isInGame
&& jjKey[KEY::MOUSE_TRACK]
&& (fly ? true : int(lastClickTime + PRECISION_FRAME_THRESHOLD) < jjGameTicks)
)
{
lastClickTime = jjGameTicks;
int x = int(jjMouseX + mimickedPlayer.cameraX - mimickedPlayer.subscreenX - jjBorderWidth);
int y = int(jjMouseY + mimickedPlayer.cameraY - mimickedPlayer.subscreenY - jjBorderHeight);
setPlayerPosition(targetPlayer, x, y, NO_PLAYER_INFORMATION, false);
}
}
void sendUpdatePositionPacket
(
jjPLAYER@ player,
int newXPos,
int newYPos,
int8 toPlayerID = NO_PLAYER_INFORMATION,
bool log = true
)
{
jjSTREAM packet;
packet.push(uint8(UPDATE_POSITION));
packet.push(player.playerID);
packet.push(toPlayerID);
packet.push(newXPos);
packet.push(newYPos);
packet.push(log);
packet.push(fly);
jjSendPacket(packet, player.clientID);
}
void onUpdatePositionPacket(jjSTREAM &in packet, int fromClientID)
{
uint8 playerID;
packet.pop(playerID);
jjPLAYER@ player = jjPlayers[playerID];
int8 toPlayerID;
packet.pop(toPlayerID);
if (player.isLocal)
{
int newXPos;
int newYPos;
bool log;
packet.pop(newXPos);
packet.pop(newYPos);
packet.pop(log);
packet.pop(fly);
setPlayerPosition(
player,
newXPos,
newYPos,
toPlayerID,
log
);
}
}
void onTakeoverPacket(jjSTREAM &in packet, int fromClientID)
{
// Why do we get those junks here? I don't know.
uint8 junk_1;
uint16 junk_2;
packet.pop(junk_1);
packet.pop(junk_2);
uint8 previousTakenOverPlayerID = takenOverPlayerID;
bool wasLax = laxTakeOver;
packet.pop(takenOverPlayerID);
packet.pop(laxTakeOver);
/* if (jjPlayers[takenOverPlayerID].isLocal && previousTakenOverPlayerID != takenOverPlayerID)
{
jjConsole(jjPlayers[0].nameUnformatted + " (the host) has gained control over your position. Follow the instructions carefully.");
return;
}
if (!jjPlayers[takenOverPlayerID].isLocal && !wasLax && jjPlayers[previousTakenOverPlayerID].isLocal)
jjConsole(jjPlayers[0].nameUnformatted + " (the host) has brought you back the privilege of freedom. Beware though.");
*/
}
void sendTakeoverPacket()
{
jjSTREAM packet;
packet.push(TAKEOVER);
packet.push(takenOverPlayerID);
packet.push(laxTakeOver);
jjSendPacket(packet);
}
void setTakenOver(uint8 value, bool lax = false)
{
takenOverPlayerID = value;
laxTakeOver = lax;
sendTakeoverPacket();
}
void logPlayerTeleportation
(
jjPLAYER@ player,
int xPos,
int yPos,
int8 toPlayerID = NO_PLAYER_INFORMATION
)
{
string teleportationInformation;
if (toPlayerID != NO_PLAYER_INFORMATION)
{
jjPLAYER@ toPlayer = jjPlayers[toPlayerID];
teleportationInformation += toPlayer.nameUnformatted + " at ";
}
teleportationInformation += formatInt(int(xPos / FRAME_PIXELS));
teleportationInformation += ", ";
teleportationInformation += formatInt(int(yPos / FRAME_PIXELS));
if (jjIsServer)
{
jjConsole(
player.nameUnformatted
+ " is being teleported to "
+ teleportationInformation
);
}
else if (player.playerID == jjLocalPlayers[0].playerID)
{
jjConsole("You are being teleported to " + teleportationInformation);
}
}
Jazz2Online © 1999-INFINITY (Site Credits). We have a Privacy Policy. Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats.
Eat your lima beans, Johnny.