приводим исходники в нормальное состояние
This commit is contained in:
71
src/main/java/com/flibitijibibo/flibitEFX/EFXEffect.java
Normal file
71
src/main/java/com/flibitijibibo/flibitEFX/EFXEffect.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Ethan "flibitijibibo" Lee
|
||||
*
|
||||
* This file is part of flibitEFX.
|
||||
*
|
||||
* flibitEFX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* flibitEFX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with flibitEFX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.flibitijibibo.flibitEFX;
|
||||
|
||||
import org.lwjgl.openal.EFX10;
|
||||
|
||||
/**
|
||||
* @author Ethan "flibitijibibo" Lee
|
||||
*/
|
||||
|
||||
public abstract class EFXEffect {
|
||||
|
||||
private int slotIndex;
|
||||
private int effectIndex;
|
||||
|
||||
/** Constructor creates an EFX effect slot containing an effect.
|
||||
* @param efxEffect The EFX10 effect type (i.e. EFX10.AL_EFFECT_REVERB)
|
||||
*/
|
||||
public EFXEffect(int efxEffect) {
|
||||
slotIndex = EFX10.alGenAuxiliaryEffectSlots();
|
||||
effectIndex = EFX10.alGenEffects();
|
||||
// TODO: Check to see if efxEffect is a valid AL_EFFECT_TYPE.
|
||||
EFX10.alEffecti(effectIndex, EFX10.AL_EFFECT_TYPE, efxEffect);
|
||||
EFX10.alAuxiliaryEffectSloti(slotIndex, EFX10.AL_EFFECTSLOT_EFFECT, effectIndex);
|
||||
}
|
||||
|
||||
/** Unloads the EFX effect and effect slot. */
|
||||
public void killEffect() {
|
||||
EFX10.alDeleteEffects(effectIndex);
|
||||
EFX10.alDeleteAuxiliaryEffectSlots(slotIndex);
|
||||
}
|
||||
|
||||
/** Returns the index of the EFX effect slot.
|
||||
* @return The index of the EFX effect slot
|
||||
*/
|
||||
public int getIndex() {
|
||||
return slotIndex;
|
||||
}
|
||||
|
||||
/** Applies an effect property to this EFX effect.
|
||||
* @param passedProperty The EFX10 effect property
|
||||
* @param passedValue The EFX10 effect value
|
||||
*/
|
||||
protected void addEffectf(int passedProperty, float passedValue) {
|
||||
EFX10.alEffectf(effectIndex, passedProperty, passedValue);
|
||||
}
|
||||
|
||||
/** Applies an effect property to this EFX effect.
|
||||
* @param passedProperty The EFX10 effect property
|
||||
* @param passedValue The EFX10 effect value
|
||||
*/
|
||||
protected void addEffecti(int passedProperty, int passedValue) {
|
||||
EFX10.alEffecti(effectIndex, passedProperty, passedValue);
|
||||
}
|
||||
}
|
||||
93
src/main/java/com/flibitijibibo/flibitEFX/EFXEffectEcho.java
Normal file
93
src/main/java/com/flibitijibibo/flibitEFX/EFXEffectEcho.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Ethan "flibitijibibo" Lee
|
||||
*
|
||||
* This file is part of flibitEFX.
|
||||
*
|
||||
* flibitEFX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* flibitEFX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with flibitEFX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.flibitijibibo.flibitEFX;
|
||||
|
||||
import org.lwjgl.openal.EFX10;
|
||||
|
||||
/**
|
||||
* @author Ethan "flibitijibibo" Lee
|
||||
*/
|
||||
|
||||
public class EFXEffectEcho extends EFXEffect {
|
||||
|
||||
/** Constructor creates a generic echo effect. */
|
||||
public EFXEffectEcho() {
|
||||
super(EFX10.AL_EFFECT_ECHO);
|
||||
}
|
||||
|
||||
/** Sets the amount of high frequency damping to apply to the echo effect.
|
||||
* @param passedValue The new damping value to apply to the echo effect
|
||||
*/
|
||||
public void setDamping(float passedValue) {
|
||||
if (passedValue < EFX10.AL_ECHO_MIN_DAMPING)
|
||||
addEffectf(EFX10.AL_ECHO_DAMPING, EFX10.AL_ECHO_MIN_DAMPING);
|
||||
else if (passedValue > EFX10.AL_ECHO_MAX_DAMPING)
|
||||
addEffectf(EFX10.AL_ECHO_DAMPING, EFX10.AL_ECHO_MAX_DAMPING);
|
||||
else
|
||||
addEffectf(EFX10.AL_ECHO_DAMPING, passedValue);
|
||||
}
|
||||
|
||||
/** Sets the echo effect's delay time.
|
||||
* @param passedValue The echo effect's new delay time
|
||||
*/
|
||||
public void setDelay(float passedValue) {
|
||||
if (passedValue < EFX10.AL_ECHO_MIN_DELAY)
|
||||
addEffectf(EFX10.AL_ECHO_DELAY, EFX10.AL_ECHO_MIN_DELAY);
|
||||
else if (passedValue > EFX10.AL_ECHO_MAX_DELAY)
|
||||
addEffectf(EFX10.AL_ECHO_DELAY, EFX10.AL_ECHO_MAX_DELAY);
|
||||
else
|
||||
addEffectf(EFX10.AL_ECHO_DELAY, passedValue);
|
||||
}
|
||||
|
||||
/** Sets the amount of feedback to echo back.
|
||||
* @param passedValue The new feedback volume of the echo effect
|
||||
*/
|
||||
public void setFeedback(float passedValue) {
|
||||
if (passedValue < EFX10.AL_ECHO_MIN_FEEDBACK)
|
||||
addEffectf(EFX10.AL_ECHO_FEEDBACK, EFX10.AL_ECHO_MIN_FEEDBACK);
|
||||
else if (passedValue > EFX10.AL_ECHO_MAX_FEEDBACK)
|
||||
addEffectf(EFX10.AL_ECHO_FEEDBACK, EFX10.AL_ECHO_MAX_FEEDBACK);
|
||||
else
|
||||
addEffectf(EFX10.AL_ECHO_FEEDBACK, passedValue);
|
||||
}
|
||||
|
||||
/** Sets the delay between each echo "tap".
|
||||
* @param passedValue The new delay time between each echo "tap"
|
||||
*/
|
||||
public void setLRDelay(float passedValue) {
|
||||
if (passedValue < EFX10.AL_ECHO_MIN_LRDELAY)
|
||||
addEffectf(EFX10.AL_ECHO_LRDELAY, EFX10.AL_ECHO_MIN_LRDELAY);
|
||||
else if (passedValue > EFX10.AL_ECHO_MAX_LRDELAY)
|
||||
addEffectf(EFX10.AL_ECHO_LRDELAY, EFX10.AL_ECHO_MAX_LRDELAY);
|
||||
else
|
||||
addEffectf(EFX10.AL_ECHO_LRDELAY, passedValue);
|
||||
}
|
||||
|
||||
/** Sets the amount of hard panning allowed for each echo.
|
||||
* @param passedValue The new level of flexibility for the echo effect's panning
|
||||
*/
|
||||
public void setSpread(float passedValue) {
|
||||
if (passedValue < EFX10.AL_ECHO_MIN_SPREAD)
|
||||
addEffectf(EFX10.AL_ECHO_SPREAD, EFX10.AL_ECHO_MIN_SPREAD);
|
||||
else if (passedValue > EFX10.AL_ECHO_MAX_SPREAD)
|
||||
addEffectf(EFX10.AL_ECHO_SPREAD, EFX10.AL_ECHO_MAX_SPREAD);
|
||||
else
|
||||
addEffectf(EFX10.AL_ECHO_SPREAD, passedValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Ethan "flibitijibibo" Lee
|
||||
*
|
||||
* This file is part of flibitEFX.
|
||||
*
|
||||
* flibitEFX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* flibitEFX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with flibitEFX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.flibitijibibo.flibitEFX;
|
||||
|
||||
import org.lwjgl.openal.EFX10;
|
||||
|
||||
/**
|
||||
* @author Ethan "flibitijibibo" Lee
|
||||
*/
|
||||
|
||||
public class EFXEffectReverb extends EFXEffect {
|
||||
|
||||
/** Constructor creates a generic reverb effect. */
|
||||
public EFXEffectReverb() {
|
||||
super(EFX10.AL_EFFECT_REVERB);
|
||||
}
|
||||
|
||||
// TODO: Add methods for all AL_EFFECT_REVERB properties.
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Ethan "flibitijibibo" Lee
|
||||
*
|
||||
* This file is part of flibitEFX.
|
||||
*
|
||||
* flibitEFX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* flibitEFX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with flibitEFX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.flibitijibibo.flibitEFX;
|
||||
|
||||
import org.lwjgl.openal.EFX10;
|
||||
|
||||
/**
|
||||
* @author Ethan "flibitijibibo" Lee
|
||||
*/
|
||||
|
||||
public class EFXEffectRingModulator extends EFXEffect {
|
||||
|
||||
public static final int SINUSOID = EFX10.AL_RING_MODULATOR_SINUSOID;
|
||||
public static final int SAWTOOTH = EFX10.AL_RING_MODULATOR_SAWTOOTH;
|
||||
public static final int SQUARE = EFX10.AL_RING_MODULATOR_SQUARE;
|
||||
|
||||
/** Constructor creates a generic ring modulator effect. */
|
||||
public EFXEffectRingModulator() {
|
||||
super(EFX10.AL_EFFECT_RING_MODULATOR);
|
||||
}
|
||||
|
||||
/** Sets the frequency of the ring modulator.
|
||||
* @param passedValue The new frequency of the ring modulator
|
||||
*/
|
||||
public void setFrequency(float passedValue) {
|
||||
if (passedValue > EFX10.AL_RING_MODULATOR_MAX_FREQUENCY)
|
||||
addEffectf(EFX10.AL_RING_MODULATOR_FREQUENCY, EFX10.AL_RING_MODULATOR_MAX_FREQUENCY);
|
||||
else if (passedValue < EFX10.AL_RING_MODULATOR_MIN_FREQUENCY)
|
||||
addEffectf(EFX10.AL_RING_MODULATOR_FREQUENCY, EFX10.AL_RING_MODULATOR_MIN_FREQUENCY);
|
||||
else
|
||||
addEffectf(EFX10.AL_RING_MODULATOR_FREQUENCY, passedValue);
|
||||
}
|
||||
|
||||
/** Sets the high-pass cutoff for the ring modulator.
|
||||
* @param passedValue The new cutoff value for the ring modulator high-pass filter
|
||||
*/
|
||||
public void setHighPassCutoff(float passedValue) {
|
||||
if (passedValue > EFX10.AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF)
|
||||
addEffectf(EFX10.AL_RING_MODULATOR_HIGHPASS_CUTOFF, EFX10.AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF);
|
||||
else if (passedValue < EFX10.AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF)
|
||||
addEffectf(EFX10.AL_RING_MODULATOR_HIGHPASS_CUTOFF, EFX10.AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF);
|
||||
else
|
||||
addEffectf(EFX10.AL_RING_MODULATOR_HIGHPASS_CUTOFF, passedValue);
|
||||
}
|
||||
|
||||
/** Sets the waveform of the ring modulator.
|
||||
* @param waveform Should be EFXEffectRingModulator.SINUSOID, SAWTOOTH or SQUARE
|
||||
*/
|
||||
public void setWaveform(int waveform) {
|
||||
if (waveform != SINUSOID && waveform != SAWTOOTH && waveform != SQUARE)
|
||||
return;
|
||||
addEffecti(EFX10.AL_RING_MODULATOR_WAVEFORM, waveform);
|
||||
}
|
||||
}
|
||||
59
src/main/java/com/flibitijibibo/flibitEFX/EFXFilter.java
Normal file
59
src/main/java/com/flibitijibibo/flibitEFX/EFXFilter.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Ethan "flibitijibibo" Lee
|
||||
*
|
||||
* This file is part of flibitEFX.
|
||||
*
|
||||
* flibitEFX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* flibitEFX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with flibitEFX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.flibitijibibo.flibitEFX;
|
||||
|
||||
import org.lwjgl.openal.EFX10;
|
||||
|
||||
/**
|
||||
* @author Ethan "flibitijibibo" Lee
|
||||
*/
|
||||
|
||||
public abstract class EFXFilter {
|
||||
|
||||
private int filterIndex;
|
||||
|
||||
/** Constructor creates an EFX effect slot containing a filter.
|
||||
* @param efxFilter The EFX10 filter type (i.e. EFX10.AL_FILTER_HIGHPASS)
|
||||
*/
|
||||
public EFXFilter(int efxFilter) {
|
||||
filterIndex = EFX10.alGenFilters();
|
||||
// TODO: Check to see if efxFilter is a valid AL_FILTER_TYPE.
|
||||
EFX10.alFilteri(filterIndex, EFX10.AL_FILTER_TYPE, efxFilter);
|
||||
}
|
||||
|
||||
/** Unloads the EFX filter. */
|
||||
public void killFilter() {
|
||||
EFX10.alDeleteFilters(filterIndex);
|
||||
}
|
||||
|
||||
/** Returns the index of the EFX filter.
|
||||
* @return The index of the EFX filter
|
||||
*/
|
||||
public int getIndex() {
|
||||
return filterIndex;
|
||||
}
|
||||
|
||||
/** Applies a filter property to this EFX filter.
|
||||
* @param passedProperty The EFX10 filter property
|
||||
* @param passedValue The EFX10 filter value
|
||||
*/
|
||||
protected void addFilter(int passedProperty, float passedValue) {
|
||||
EFX10.alFilterf(filterIndex, passedProperty, passedValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Ethan "flibitijibibo" Lee
|
||||
*
|
||||
* This file is part of flibitEFX.
|
||||
*
|
||||
* flibitEFX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* flibitEFX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with flibitEFX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.flibitijibibo.flibitEFX;
|
||||
|
||||
import org.lwjgl.openal.EFX10;
|
||||
|
||||
/**
|
||||
* @author Ethan "flibitijibibo" Lee
|
||||
*/
|
||||
|
||||
public class EFXFilterLowPass extends EFXFilter {
|
||||
|
||||
/** Constructor creates a generic low-pass filter. */
|
||||
public EFXFilterLowPass() {
|
||||
super(EFX10.AL_FILTER_LOWPASS);
|
||||
}
|
||||
|
||||
/** Sets the gain of the low-pass filter.
|
||||
* @param passedValue The new value of the low-pass filter gain
|
||||
*/
|
||||
public void setGain(float passedValue) {
|
||||
addFilter(EFX10.AL_LOWPASS_GAIN, passedValue);
|
||||
}
|
||||
|
||||
/** Sets the gain of the low-pass filter's high frequencies.
|
||||
* @param passedValue The new value of the low-pass filter's HF gain
|
||||
*/
|
||||
public void setGainHF(float passedValue) {
|
||||
addFilter(EFX10.AL_LOWPASS_GAINHF, passedValue);
|
||||
}
|
||||
}
|
||||
1362
src/main/java/lwjake2/Defines.java
Normal file
1362
src/main/java/lwjake2/Defines.java
Normal file
File diff suppressed because it is too large
Load Diff
389
src/main/java/lwjake2/Globals.java
Normal file
389
src/main/java/lwjake2/Globals.java
Normal file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2;
|
||||
|
||||
import lwjake2.client.centity_t;
|
||||
import lwjake2.client.client_state_t;
|
||||
import lwjake2.client.client_static_t;
|
||||
import lwjake2.client.console_t;
|
||||
import lwjake2.client.refexport_t;
|
||||
import lwjake2.client.viddef_t;
|
||||
import lwjake2.client.vrect_t;
|
||||
import lwjake2.game.cmdalias_t;
|
||||
import lwjake2.game.cvar_t;
|
||||
import lwjake2.game.entity_state_t;
|
||||
import lwjake2.qcommon.netadr_t;
|
||||
import lwjake2.qcommon.sizebuf_t;
|
||||
import lwjake2.render.DummyRenderer;
|
||||
import lwjake2.render.model_t;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Globals ist the collection of global variables and constants.
|
||||
* It is more elegant to use these vars by inheritance to separate
|
||||
* it with eclipse refactoring later.
|
||||
*
|
||||
* As consequence you dont have to touch that much code this time.
|
||||
*/
|
||||
public class Globals extends Defines {
|
||||
|
||||
public static final String __DATE__ = "2003";
|
||||
|
||||
public static final float VERSION = 3.21f;
|
||||
|
||||
public static final String BASEDIRNAME = "baseq2";
|
||||
|
||||
/*
|
||||
* global variables
|
||||
*/
|
||||
public static int curtime = 0;
|
||||
public static boolean cmd_wait;
|
||||
|
||||
public static int alias_count;
|
||||
public static int c_traces;
|
||||
public static int c_brush_traces;
|
||||
public static int c_pointcontents;
|
||||
public static int server_state;
|
||||
|
||||
public static cvar_t cl_add_blend;
|
||||
public static cvar_t cl_add_entities;
|
||||
public static cvar_t cl_add_lights;
|
||||
public static cvar_t cl_add_particles;
|
||||
public static cvar_t cl_anglespeedkey;
|
||||
public static cvar_t cl_autoskins;
|
||||
public static cvar_t cl_footsteps;
|
||||
public static cvar_t cl_forwardspeed;
|
||||
public static cvar_t cl_gun;
|
||||
public static cvar_t cl_maxfps;
|
||||
public static cvar_t cl_noskins;
|
||||
public static cvar_t cl_pitchspeed;
|
||||
public static cvar_t cl_predict;
|
||||
public static cvar_t cl_run;
|
||||
public static cvar_t cl_sidespeed;
|
||||
public static cvar_t cl_stereo;
|
||||
public static cvar_t cl_stereo_separation;
|
||||
public static cvar_t cl_timedemo = new cvar_t();
|
||||
public static cvar_t cl_timeout;
|
||||
public static cvar_t cl_upspeed;
|
||||
public static cvar_t cl_yawspeed;
|
||||
public static cvar_t dedicated;
|
||||
public static cvar_t developer;
|
||||
public static cvar_t fixedtime;
|
||||
public static cvar_t freelook;
|
||||
public static cvar_t host_speeds;
|
||||
public static cvar_t log_stats;
|
||||
public static cvar_t logfile_active;
|
||||
public static cvar_t lookspring;
|
||||
public static cvar_t lookstrafe;
|
||||
public static cvar_t nostdout;
|
||||
public static cvar_t sensitivity;
|
||||
public static cvar_t showtrace;
|
||||
public static cvar_t timescale;
|
||||
public static cvar_t in_mouse;
|
||||
public static cvar_t in_joystick;
|
||||
|
||||
|
||||
public static sizebuf_t net_message = new sizebuf_t();
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
COMMAND BUFFER
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
public static sizebuf_t cmd_text = new sizebuf_t();
|
||||
|
||||
public static byte defer_text_buf[] = new byte[8192];
|
||||
|
||||
public static byte cmd_text_buf[] = new byte[8192];
|
||||
public static cmdalias_t cmd_alias;
|
||||
|
||||
//=============================================================================
|
||||
|
||||
public static byte[] net_message_buffer = new byte[MAX_MSGLEN];
|
||||
|
||||
public static int time_before_game;
|
||||
public static int time_after_game;
|
||||
public static int time_before_ref;
|
||||
public static int time_after_ref;
|
||||
|
||||
public static FileWriter log_stats_file = null;
|
||||
|
||||
public static cvar_t m_pitch;
|
||||
public static cvar_t m_yaw;
|
||||
public static cvar_t m_forward;
|
||||
public static cvar_t m_side;
|
||||
|
||||
public static cvar_t cl_lightlevel;
|
||||
|
||||
//
|
||||
// userinfo
|
||||
//
|
||||
public static cvar_t info_password;
|
||||
public static cvar_t info_spectator;
|
||||
public static cvar_t name;
|
||||
public static cvar_t skin;
|
||||
public static cvar_t rate;
|
||||
public static cvar_t fov;
|
||||
public static cvar_t msg;
|
||||
public static cvar_t hand;
|
||||
public static cvar_t gender;
|
||||
public static cvar_t gender_auto;
|
||||
|
||||
public static cvar_t cl_vwep;
|
||||
|
||||
public static client_static_t cls = new client_static_t();
|
||||
public static client_state_t cl = new client_state_t();
|
||||
|
||||
public static centity_t cl_entities[] = new centity_t[Defines.MAX_EDICTS];
|
||||
static {
|
||||
for (int i = 0; i < cl_entities.length; i++) {
|
||||
cl_entities[i] = new centity_t();
|
||||
}
|
||||
}
|
||||
|
||||
public static entity_state_t cl_parse_entities[] = new entity_state_t[Defines.MAX_PARSE_ENTITIES];
|
||||
|
||||
static {
|
||||
for (int i = 0; i < cl_parse_entities.length; i++)
|
||||
{
|
||||
cl_parse_entities[i] = new entity_state_t(null);
|
||||
}
|
||||
}
|
||||
|
||||
public static cvar_t rcon_client_password;
|
||||
public static cvar_t rcon_address;
|
||||
|
||||
public static cvar_t cl_shownet;
|
||||
public static cvar_t cl_showmiss;
|
||||
public static cvar_t cl_showclamp;
|
||||
|
||||
public static cvar_t cl_paused;
|
||||
|
||||
// client/anorms.h
|
||||
public static final float bytedirs[][] = { /**
|
||||
*/
|
||||
{ -0.525731f, 0.000000f, 0.850651f }, {
|
||||
-0.442863f, 0.238856f, 0.864188f }, {
|
||||
-0.295242f, 0.000000f, 0.955423f }, {
|
||||
-0.309017f, 0.500000f, 0.809017f }, {
|
||||
-0.162460f, 0.262866f, 0.951056f }, {
|
||||
0.000000f, 0.000000f, 1.000000f }, {
|
||||
0.000000f, 0.850651f, 0.525731f }, {
|
||||
-0.147621f, 0.716567f, 0.681718f }, {
|
||||
0.147621f, 0.716567f, 0.681718f }, {
|
||||
0.000000f, 0.525731f, 0.850651f }, {
|
||||
0.309017f, 0.500000f, 0.809017f }, {
|
||||
0.525731f, 0.000000f, 0.850651f }, {
|
||||
0.295242f, 0.000000f, 0.955423f }, {
|
||||
0.442863f, 0.238856f, 0.864188f }, {
|
||||
0.162460f, 0.262866f, 0.951056f }, {
|
||||
-0.681718f, 0.147621f, 0.716567f }, {
|
||||
-0.809017f, 0.309017f, 0.500000f }, {
|
||||
-0.587785f, 0.425325f, 0.688191f }, {
|
||||
-0.850651f, 0.525731f, 0.000000f }, {
|
||||
-0.864188f, 0.442863f, 0.238856f }, {
|
||||
-0.716567f, 0.681718f, 0.147621f }, {
|
||||
-0.688191f, 0.587785f, 0.425325f }, {
|
||||
-0.500000f, 0.809017f, 0.309017f }, {
|
||||
-0.238856f, 0.864188f, 0.442863f }, {
|
||||
-0.425325f, 0.688191f, 0.587785f }, {
|
||||
-0.716567f, 0.681718f, -0.147621f }, {
|
||||
-0.500000f, 0.809017f, -0.309017f }, {
|
||||
-0.525731f, 0.850651f, 0.000000f }, {
|
||||
0.000000f, 0.850651f, -0.525731f }, {
|
||||
-0.238856f, 0.864188f, -0.442863f }, {
|
||||
0.000000f, 0.955423f, -0.295242f }, {
|
||||
-0.262866f, 0.951056f, -0.162460f }, {
|
||||
0.000000f, 1.000000f, 0.000000f }, {
|
||||
0.000000f, 0.955423f, 0.295242f }, {
|
||||
-0.262866f, 0.951056f, 0.162460f }, {
|
||||
0.238856f, 0.864188f, 0.442863f }, {
|
||||
0.262866f, 0.951056f, 0.162460f }, {
|
||||
0.500000f, 0.809017f, 0.309017f }, {
|
||||
0.238856f, 0.864188f, -0.442863f }, {
|
||||
0.262866f, 0.951056f, -0.162460f }, {
|
||||
0.500000f, 0.809017f, -0.309017f }, {
|
||||
0.850651f, 0.525731f, 0.000000f }, {
|
||||
0.716567f, 0.681718f, 0.147621f }, {
|
||||
0.716567f, 0.681718f, -0.147621f }, {
|
||||
0.525731f, 0.850651f, 0.000000f }, {
|
||||
0.425325f, 0.688191f, 0.587785f }, {
|
||||
0.864188f, 0.442863f, 0.238856f }, {
|
||||
0.688191f, 0.587785f, 0.425325f }, {
|
||||
0.809017f, 0.309017f, 0.500000f }, {
|
||||
0.681718f, 0.147621f, 0.716567f }, {
|
||||
0.587785f, 0.425325f, 0.688191f }, {
|
||||
0.955423f, 0.295242f, 0.000000f }, {
|
||||
1.000000f, 0.000000f, 0.000000f }, {
|
||||
0.951056f, 0.162460f, 0.262866f }, {
|
||||
0.850651f, -0.525731f, 0.000000f }, {
|
||||
0.955423f, -0.295242f, 0.000000f }, {
|
||||
0.864188f, -0.442863f, 0.238856f }, {
|
||||
0.951056f, -0.162460f, 0.262866f }, {
|
||||
0.809017f, -0.309017f, 0.500000f }, {
|
||||
0.681718f, -0.147621f, 0.716567f }, {
|
||||
0.850651f, 0.000000f, 0.525731f }, {
|
||||
0.864188f, 0.442863f, -0.238856f }, {
|
||||
0.809017f, 0.309017f, -0.500000f }, {
|
||||
0.951056f, 0.162460f, -0.262866f }, {
|
||||
0.525731f, 0.000000f, -0.850651f }, {
|
||||
0.681718f, 0.147621f, -0.716567f }, {
|
||||
0.681718f, -0.147621f, -0.716567f }, {
|
||||
0.850651f, 0.000000f, -0.525731f }, {
|
||||
0.809017f, -0.309017f, -0.500000f }, {
|
||||
0.864188f, -0.442863f, -0.238856f }, {
|
||||
0.951056f, -0.162460f, -0.262866f }, {
|
||||
0.147621f, 0.716567f, -0.681718f }, {
|
||||
0.309017f, 0.500000f, -0.809017f }, {
|
||||
0.425325f, 0.688191f, -0.587785f }, {
|
||||
0.442863f, 0.238856f, -0.864188f }, {
|
||||
0.587785f, 0.425325f, -0.688191f }, {
|
||||
0.688191f, 0.587785f, -0.425325f }, {
|
||||
-0.147621f, 0.716567f, -0.681718f }, {
|
||||
-0.309017f, 0.500000f, -0.809017f }, {
|
||||
0.000000f, 0.525731f, -0.850651f }, {
|
||||
-0.525731f, 0.000000f, -0.850651f }, {
|
||||
-0.442863f, 0.238856f, -0.864188f }, {
|
||||
-0.295242f, 0.000000f, -0.955423f }, {
|
||||
-0.162460f, 0.262866f, -0.951056f }, {
|
||||
0.000000f, 0.000000f, -1.000000f }, {
|
||||
0.295242f, 0.000000f, -0.955423f }, {
|
||||
0.162460f, 0.262866f, -0.951056f }, {
|
||||
-0.442863f, -0.238856f, -0.864188f }, {
|
||||
-0.309017f, -0.500000f, -0.809017f }, {
|
||||
-0.162460f, -0.262866f, -0.951056f }, {
|
||||
0.000000f, -0.850651f, -0.525731f }, {
|
||||
-0.147621f, -0.716567f, -0.681718f }, {
|
||||
0.147621f, -0.716567f, -0.681718f }, {
|
||||
0.000000f, -0.525731f, -0.850651f }, {
|
||||
0.309017f, -0.500000f, -0.809017f }, {
|
||||
0.442863f, -0.238856f, -0.864188f }, {
|
||||
0.162460f, -0.262866f, -0.951056f }, {
|
||||
0.238856f, -0.864188f, -0.442863f }, {
|
||||
0.500000f, -0.809017f, -0.309017f }, {
|
||||
0.425325f, -0.688191f, -0.587785f }, {
|
||||
0.716567f, -0.681718f, -0.147621f }, {
|
||||
0.688191f, -0.587785f, -0.425325f }, {
|
||||
0.587785f, -0.425325f, -0.688191f }, {
|
||||
0.000000f, -0.955423f, -0.295242f }, {
|
||||
0.000000f, -1.000000f, 0.000000f }, {
|
||||
0.262866f, -0.951056f, -0.162460f }, {
|
||||
0.000000f, -0.850651f, 0.525731f }, {
|
||||
0.000000f, -0.955423f, 0.295242f }, {
|
||||
0.238856f, -0.864188f, 0.442863f }, {
|
||||
0.262866f, -0.951056f, 0.162460f }, {
|
||||
0.500000f, -0.809017f, 0.309017f }, {
|
||||
0.716567f, -0.681718f, 0.147621f }, {
|
||||
0.525731f, -0.850651f, 0.000000f }, {
|
||||
-0.238856f, -0.864188f, -0.442863f }, {
|
||||
-0.500000f, -0.809017f, -0.309017f }, {
|
||||
-0.262866f, -0.951056f, -0.162460f }, {
|
||||
-0.850651f, -0.525731f, 0.000000f }, {
|
||||
-0.716567f, -0.681718f, -0.147621f }, {
|
||||
-0.716567f, -0.681718f, 0.147621f }, {
|
||||
-0.525731f, -0.850651f, 0.000000f }, {
|
||||
-0.500000f, -0.809017f, 0.309017f }, {
|
||||
-0.238856f, -0.864188f, 0.442863f }, {
|
||||
-0.262866f, -0.951056f, 0.162460f }, {
|
||||
-0.864188f, -0.442863f, 0.238856f }, {
|
||||
-0.809017f, -0.309017f, 0.500000f }, {
|
||||
-0.688191f, -0.587785f, 0.425325f }, {
|
||||
-0.681718f, -0.147621f, 0.716567f }, {
|
||||
-0.442863f, -0.238856f, 0.864188f }, {
|
||||
-0.587785f, -0.425325f, 0.688191f }, {
|
||||
-0.309017f, -0.500000f, 0.809017f }, {
|
||||
-0.147621f, -0.716567f, 0.681718f }, {
|
||||
-0.425325f, -0.688191f, 0.587785f }, {
|
||||
-0.162460f, -0.262866f, 0.951056f }, {
|
||||
0.442863f, -0.238856f, 0.864188f }, {
|
||||
0.162460f, -0.262866f, 0.951056f }, {
|
||||
0.309017f, -0.500000f, 0.809017f }, {
|
||||
0.147621f, -0.716567f, 0.681718f }, {
|
||||
0.000000f, -0.525731f, 0.850651f }, {
|
||||
0.425325f, -0.688191f, 0.587785f }, {
|
||||
0.587785f, -0.425325f, 0.688191f }, {
|
||||
0.688191f, -0.587785f, 0.425325f }, {
|
||||
-0.955423f, 0.295242f, 0.000000f }, {
|
||||
-0.951056f, 0.162460f, 0.262866f }, {
|
||||
-1.000000f, 0.000000f, 0.000000f }, {
|
||||
-0.850651f, 0.000000f, 0.525731f }, {
|
||||
-0.955423f, -0.295242f, 0.000000f }, {
|
||||
-0.951056f, -0.162460f, 0.262866f }, {
|
||||
-0.864188f, 0.442863f, -0.238856f }, {
|
||||
-0.951056f, 0.162460f, -0.262866f }, {
|
||||
-0.809017f, 0.309017f, -0.500000f }, {
|
||||
-0.864188f, -0.442863f, -0.238856f }, {
|
||||
-0.951056f, -0.162460f, -0.262866f }, {
|
||||
-0.809017f, -0.309017f, -0.500000f }, {
|
||||
-0.681718f, 0.147621f, -0.716567f }, {
|
||||
-0.681718f, -0.147621f, -0.716567f }, {
|
||||
-0.850651f, 0.000000f, -0.525731f }, {
|
||||
-0.688191f, 0.587785f, -0.425325f }, {
|
||||
-0.587785f, 0.425325f, -0.688191f }, {
|
||||
-0.425325f, 0.688191f, -0.587785f }, {
|
||||
-0.425325f, -0.688191f, -0.587785f }, {
|
||||
-0.587785f, -0.425325f, -0.688191f }, {
|
||||
-0.688191f, -0.587785f, -0.425325f }
|
||||
};
|
||||
|
||||
public static boolean userinfo_modified = false;
|
||||
|
||||
public static cvar_t cvar_vars;
|
||||
public static final console_t con = new console_t();
|
||||
public static cvar_t con_notifytime;
|
||||
public static viddef_t viddef = new viddef_t();
|
||||
// Renderer interface used by VID, SCR, ...
|
||||
public static refexport_t re = new DummyRenderer();
|
||||
|
||||
public static String[] keybindings = new String[256];
|
||||
public static boolean[] keydown = new boolean[256];
|
||||
public static boolean chat_team = false;
|
||||
public static String chat_buffer = "";
|
||||
public static byte[][] key_lines = new byte[32][];
|
||||
public static int key_linepos;
|
||||
static {
|
||||
for (int i = 0; i < key_lines.length; i++)
|
||||
key_lines[i] = new byte[Defines.MAXCMDLINE];
|
||||
};
|
||||
public static int edit_line;
|
||||
|
||||
public static cvar_t crosshair;
|
||||
public static vrect_t scr_vrect = new vrect_t();
|
||||
public static int sys_frame_time;
|
||||
public static int chat_bufferlen = 0;
|
||||
public static int gun_frame;
|
||||
public static model_t gun_model;
|
||||
public static netadr_t net_from = new netadr_t();
|
||||
|
||||
// logfile
|
||||
public static RandomAccessFile logfile = null;
|
||||
|
||||
public static float vec3_origin[] = { 0.0f, 0.0f, 0.0f };
|
||||
|
||||
public static cvar_t m_filter;
|
||||
public static int vidref_val = VIDREF_GL;
|
||||
|
||||
public static Random rnd = new Random();
|
||||
}
|
||||
95
src/main/java/lwjake2/LWJake2.java
Normal file
95
src/main/java/lwjake2/LWJake2.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.qcommon.Cvar;
|
||||
import lwjake2.qcommon.Qcommon;
|
||||
import lwjake2.sys.Timer;
|
||||
|
||||
/**
|
||||
* Jake2 is the main class of Quake2 for Java.
|
||||
*/
|
||||
public final class LWJake2 {
|
||||
|
||||
/**
|
||||
* main is used to start the game. Quake2 for Java supports the following
|
||||
* command line arguments:
|
||||
*
|
||||
* @param args
|
||||
*/
|
||||
public static void main(@NonNull String[] args) {
|
||||
|
||||
boolean dedicated = false;
|
||||
|
||||
// check if we are in dedicated mode to hide the java dialog.
|
||||
for (int n = 0; n < args.length; n++)
|
||||
{
|
||||
if (args[n].equals("+set"))
|
||||
{
|
||||
if (n++ >= args.length)
|
||||
break;
|
||||
|
||||
if (!args[n].equals("dedicated"))
|
||||
continue;
|
||||
|
||||
if (n++ >= args.length)
|
||||
break;
|
||||
|
||||
if (args[n].equals("1") || args[n].equals("\"1\""))
|
||||
{
|
||||
Com.Printf("Starting in dedicated mode.\n");
|
||||
dedicated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: check if dedicated is set in config file
|
||||
|
||||
Globals.dedicated= Cvar.Get("dedicated", "0", Qcommon.CVAR_NOSET);
|
||||
|
||||
if (dedicated)
|
||||
Globals.dedicated.value = 1.0f;
|
||||
|
||||
// in C the first arg is the filename
|
||||
int argc = (args == null) ? 1 : args.length + 1;
|
||||
String[] c_args = new String[argc];
|
||||
c_args[0] = "LWJake2";
|
||||
if (argc > 1) {
|
||||
System.arraycopy(args, 0, c_args, 1, argc - 1);
|
||||
}
|
||||
Qcommon.Init(c_args);
|
||||
|
||||
Globals.nostdout = Cvar.Get("nostdout", "0", 0);
|
||||
|
||||
int oldtime = Timer.Milliseconds();
|
||||
int newtime;
|
||||
int time;
|
||||
while (true) {
|
||||
// find time spending rendering last frame
|
||||
newtime = Timer.Milliseconds();
|
||||
time = newtime - oldtime;
|
||||
|
||||
if (time > 0)
|
||||
Qcommon.Frame(time);
|
||||
oldtime = newtime;
|
||||
}
|
||||
}
|
||||
}
|
||||
1598
src/main/java/lwjake2/client/CL.java
Normal file
1598
src/main/java/lwjake2/client/CL.java
Normal file
File diff suppressed because it is too large
Load Diff
1214
src/main/java/lwjake2/client/CL_ents.java
Normal file
1214
src/main/java/lwjake2/client/CL_ents.java
Normal file
File diff suppressed because it is too large
Load Diff
2166
src/main/java/lwjake2/client/CL_fx.java
Normal file
2166
src/main/java/lwjake2/client/CL_fx.java
Normal file
File diff suppressed because it is too large
Load Diff
622
src/main/java/lwjake2/client/CL_input.java
Normal file
622
src/main/java/lwjake2/client/CL_input.java
Normal file
@@ -0,0 +1,622 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.game.Cmd;
|
||||
import lwjake2.game.cvar_t;
|
||||
import lwjake2.game.usercmd_t;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.qcommon.Cvar;
|
||||
import lwjake2.qcommon.MSG;
|
||||
import lwjake2.qcommon.Netchan;
|
||||
import lwjake2.qcommon.SZ;
|
||||
import lwjake2.qcommon.sizebuf_t;
|
||||
import lwjake2.sys.IN;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
/**
|
||||
* CL_input
|
||||
*/
|
||||
public class CL_input {
|
||||
|
||||
static long frame_msec;
|
||||
|
||||
static long old_sys_frame_time;
|
||||
|
||||
static cvar_t cl_nodelta;
|
||||
|
||||
/*
|
||||
* ===============================================================================
|
||||
*
|
||||
* KEY BUTTONS
|
||||
*
|
||||
* Continuous button event tracking is complicated by the fact that two
|
||||
* different input sources (say, mouse button 1 and the control key) can
|
||||
* both press the same button, but the button should only be released when
|
||||
* both of the pressing key have been released.
|
||||
*
|
||||
* When a key event issues a button command (+forward, +attack, etc), it
|
||||
* appends its key number as a parameter to the command so it can be matched
|
||||
* up with the release.
|
||||
*
|
||||
* state bit 0 is the current state of the key state bit 1 is edge triggered
|
||||
* on the up to down transition state bit 2 is edge triggered on the down to
|
||||
* up transition
|
||||
*
|
||||
*
|
||||
* Key_Event (int key, qboolean down, unsigned time);
|
||||
*
|
||||
* +mlook src time
|
||||
*
|
||||
* ===============================================================================
|
||||
*/
|
||||
|
||||
static kbutton_t in_klook = new kbutton_t();
|
||||
|
||||
static kbutton_t in_left = new kbutton_t();
|
||||
|
||||
static kbutton_t in_right = new kbutton_t();
|
||||
|
||||
static kbutton_t in_forward = new kbutton_t();
|
||||
|
||||
static kbutton_t in_back = new kbutton_t();
|
||||
|
||||
static kbutton_t in_lookup = new kbutton_t();
|
||||
|
||||
static kbutton_t in_lookdown = new kbutton_t();
|
||||
|
||||
static kbutton_t in_moveleft = new kbutton_t();
|
||||
|
||||
static kbutton_t in_moveright = new kbutton_t();
|
||||
|
||||
public static kbutton_t in_strafe = new kbutton_t();
|
||||
|
||||
static kbutton_t in_speed = new kbutton_t();
|
||||
|
||||
static kbutton_t in_use = new kbutton_t();
|
||||
|
||||
static kbutton_t in_attack = new kbutton_t();
|
||||
|
||||
static kbutton_t in_up = new kbutton_t();
|
||||
|
||||
static kbutton_t in_down = new kbutton_t();
|
||||
|
||||
static int in_impulse;
|
||||
|
||||
static void KeyDown(kbutton_t b) {
|
||||
int k;
|
||||
String c;
|
||||
|
||||
c = Cmd.Argv(1);
|
||||
if (c.length() > 0)
|
||||
k = Lib.atoi(c);
|
||||
else
|
||||
k = -1; // typed manually at the console for continuous down
|
||||
|
||||
if (k == b.down[0] || k == b.down[1])
|
||||
return; // repeating key
|
||||
|
||||
if (b.down[0] == 0)
|
||||
b.down[0] = k;
|
||||
else if (b.down[1] == 0)
|
||||
b.down[1] = k;
|
||||
else {
|
||||
Com.Printf("Three keys down for a button!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((b.state & 1) != 0)
|
||||
return; // still down
|
||||
|
||||
// save timestamp
|
||||
c = Cmd.Argv(2);
|
||||
b.downtime = Lib.atoi(c);
|
||||
if (b.downtime == 0)
|
||||
b.downtime = Globals.sys_frame_time - 100;
|
||||
|
||||
b.state |= 3; // down + impulse down
|
||||
}
|
||||
|
||||
static void KeyUp(kbutton_t b) {
|
||||
int k;
|
||||
String c;
|
||||
int uptime;
|
||||
|
||||
c = Cmd.Argv(1);
|
||||
if (c.length() > 0)
|
||||
k = Lib.atoi(c);
|
||||
else {
|
||||
// typed manually at the console, assume for unsticking, so clear
|
||||
// all
|
||||
b.down[0] = b.down[1] = 0;
|
||||
b.state = 4; // impulse up
|
||||
return;
|
||||
}
|
||||
|
||||
if (b.down[0] == k)
|
||||
b.down[0] = 0;
|
||||
else if (b.down[1] == k)
|
||||
b.down[1] = 0;
|
||||
else
|
||||
return; // key up without coresponding down (menu pass through)
|
||||
if (b.down[0] != 0 || b.down[1] != 0)
|
||||
return; // some other key is still holding it down
|
||||
|
||||
if ((b.state & 1) == 0)
|
||||
return; // still up (this should not happen)
|
||||
|
||||
// save timestamp
|
||||
c = Cmd.Argv(2);
|
||||
uptime = Lib.atoi(c);
|
||||
if (uptime != 0)
|
||||
b.msec += uptime - b.downtime;
|
||||
else
|
||||
b.msec += 10;
|
||||
|
||||
b.state &= ~1; // now up
|
||||
b.state |= 4; // impulse up
|
||||
}
|
||||
|
||||
static void IN_KLookDown() {
|
||||
KeyDown(in_klook);
|
||||
}
|
||||
|
||||
static void IN_KLookUp() {
|
||||
KeyUp(in_klook);
|
||||
}
|
||||
|
||||
static void IN_UpDown() {
|
||||
KeyDown(in_up);
|
||||
}
|
||||
|
||||
static void IN_UpUp() {
|
||||
KeyUp(in_up);
|
||||
}
|
||||
|
||||
static void IN_DownDown() {
|
||||
KeyDown(in_down);
|
||||
}
|
||||
|
||||
static void IN_DownUp() {
|
||||
KeyUp(in_down);
|
||||
}
|
||||
|
||||
static void IN_LeftDown() {
|
||||
KeyDown(in_left);
|
||||
}
|
||||
|
||||
static void IN_LeftUp() {
|
||||
KeyUp(in_left);
|
||||
}
|
||||
|
||||
static void IN_RightDown() {
|
||||
KeyDown(in_right);
|
||||
}
|
||||
|
||||
static void IN_RightUp() {
|
||||
KeyUp(in_right);
|
||||
}
|
||||
|
||||
static void IN_ForwardDown() {
|
||||
KeyDown(in_forward);
|
||||
}
|
||||
|
||||
static void IN_ForwardUp() {
|
||||
KeyUp(in_forward);
|
||||
}
|
||||
|
||||
static void IN_BackDown() {
|
||||
KeyDown(in_back);
|
||||
}
|
||||
|
||||
static void IN_BackUp() {
|
||||
KeyUp(in_back);
|
||||
}
|
||||
|
||||
static void IN_LookupDown() {
|
||||
KeyDown(in_lookup);
|
||||
}
|
||||
|
||||
static void IN_LookupUp() {
|
||||
KeyUp(in_lookup);
|
||||
}
|
||||
|
||||
static void IN_LookdownDown() {
|
||||
KeyDown(in_lookdown);
|
||||
}
|
||||
|
||||
static void IN_LookdownUp() {
|
||||
KeyUp(in_lookdown);
|
||||
}
|
||||
|
||||
static void IN_MoveleftDown() {
|
||||
KeyDown(in_moveleft);
|
||||
}
|
||||
|
||||
static void IN_MoveleftUp() {
|
||||
KeyUp(in_moveleft);
|
||||
}
|
||||
|
||||
static void IN_MoverightDown() {
|
||||
KeyDown(in_moveright);
|
||||
}
|
||||
|
||||
static void IN_MoverightUp() {
|
||||
KeyUp(in_moveright);
|
||||
}
|
||||
|
||||
static void IN_SpeedDown() {
|
||||
KeyDown(in_speed);
|
||||
}
|
||||
|
||||
static void IN_SpeedUp() {
|
||||
KeyUp(in_speed);
|
||||
}
|
||||
|
||||
static void IN_StrafeDown() {
|
||||
KeyDown(in_strafe);
|
||||
}
|
||||
|
||||
static void IN_StrafeUp() {
|
||||
KeyUp(in_strafe);
|
||||
}
|
||||
|
||||
static void IN_AttackDown() {
|
||||
KeyDown(in_attack);
|
||||
}
|
||||
|
||||
static void IN_AttackUp() {
|
||||
KeyUp(in_attack);
|
||||
}
|
||||
|
||||
static void IN_UseDown() {
|
||||
KeyDown(in_use);
|
||||
}
|
||||
|
||||
static void IN_UseUp() {
|
||||
KeyUp(in_use);
|
||||
}
|
||||
|
||||
static void IN_Impulse() {
|
||||
in_impulse = Lib.atoi(Cmd.Argv(1));
|
||||
}
|
||||
|
||||
/*
|
||||
* =============== CL_KeyState
|
||||
*
|
||||
* Returns the fraction of the frame that the key was down ===============
|
||||
*/
|
||||
static float KeyState(kbutton_t key) {
|
||||
float val;
|
||||
long msec;
|
||||
|
||||
key.state &= 1; // clear impulses
|
||||
|
||||
msec = key.msec;
|
||||
key.msec = 0;
|
||||
|
||||
if (key.state != 0) {
|
||||
// still down
|
||||
msec += Globals.sys_frame_time - key.downtime;
|
||||
key.downtime = Globals.sys_frame_time;
|
||||
}
|
||||
|
||||
val = (float) msec / frame_msec;
|
||||
if (val < 0)
|
||||
val = 0;
|
||||
if (val > 1)
|
||||
val = 1;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
|
||||
/*
|
||||
* ================ CL_AdjustAngles
|
||||
*
|
||||
* Moves the local angle positions ================
|
||||
*/
|
||||
static void AdjustAngles() {
|
||||
float speed;
|
||||
float up, down;
|
||||
|
||||
if ((in_speed.state & 1) != 0)
|
||||
speed = Globals.cls.frametime * Globals.cl_anglespeedkey.value;
|
||||
else
|
||||
speed = Globals.cls.frametime;
|
||||
|
||||
if ((in_strafe.state & 1) == 0) {
|
||||
Globals.cl.viewangles[Defines.YAW] -= speed * Globals.cl_yawspeed.value * KeyState(in_right);
|
||||
Globals.cl.viewangles[Defines.YAW] += speed * Globals.cl_yawspeed.value * KeyState(in_left);
|
||||
}
|
||||
if ((in_klook.state & 1) != 0) {
|
||||
Globals.cl.viewangles[Defines.PITCH] -= speed * Globals.cl_pitchspeed.value * KeyState(in_forward);
|
||||
Globals.cl.viewangles[Defines.PITCH] += speed * Globals.cl_pitchspeed.value * KeyState(in_back);
|
||||
}
|
||||
|
||||
up = KeyState(in_lookup);
|
||||
down = KeyState(in_lookdown);
|
||||
|
||||
Globals.cl.viewangles[Defines.PITCH] -= speed * Globals.cl_pitchspeed.value * up;
|
||||
Globals.cl.viewangles[Defines.PITCH] += speed * Globals.cl_pitchspeed.value * down;
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ CL_BaseMove
|
||||
*
|
||||
* Send the intended movement message to the server ================
|
||||
*/
|
||||
static void BaseMove(usercmd_t cmd) {
|
||||
AdjustAngles();
|
||||
|
||||
//memset (cmd, 0, sizeof(*cmd));
|
||||
cmd.clear();
|
||||
|
||||
Math3D.VectorCopy(Globals.cl.viewangles, cmd.angles);
|
||||
if ((in_strafe.state & 1) != 0) {
|
||||
cmd.sidemove += Globals.cl_sidespeed.value * KeyState(in_right);
|
||||
cmd.sidemove -= Globals.cl_sidespeed.value * KeyState(in_left);
|
||||
}
|
||||
|
||||
cmd.sidemove += Globals.cl_sidespeed.value * KeyState(in_moveright);
|
||||
cmd.sidemove -= Globals.cl_sidespeed.value * KeyState(in_moveleft);
|
||||
|
||||
cmd.upmove += Globals.cl_upspeed.value * KeyState(in_up);
|
||||
cmd.upmove -= Globals.cl_upspeed.value * KeyState(in_down);
|
||||
|
||||
if ((in_klook.state & 1) == 0) {
|
||||
cmd.forwardmove += Globals.cl_forwardspeed.value * KeyState(in_forward);
|
||||
cmd.forwardmove -= Globals.cl_forwardspeed.value * KeyState(in_back);
|
||||
}
|
||||
|
||||
//
|
||||
// adjust for speed key / running
|
||||
//
|
||||
if (((in_speed.state & 1) ^ (int) (Globals.cl_run.value)) != 0) {
|
||||
cmd.forwardmove *= 2;
|
||||
cmd.sidemove *= 2;
|
||||
cmd.upmove *= 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void ClampPitch() {
|
||||
|
||||
float pitch;
|
||||
|
||||
pitch = Math3D.SHORT2ANGLE(Globals.cl.frame.playerstate.pmove.delta_angles[Defines.PITCH]);
|
||||
if (pitch > 180)
|
||||
pitch -= 360;
|
||||
|
||||
if (Globals.cl.viewangles[Defines.PITCH] + pitch < -360)
|
||||
Globals.cl.viewangles[Defines.PITCH] += 360; // wrapped
|
||||
if (Globals.cl.viewangles[Defines.PITCH] + pitch > 360)
|
||||
Globals.cl.viewangles[Defines.PITCH] -= 360; // wrapped
|
||||
|
||||
if (Globals.cl.viewangles[Defines.PITCH] + pitch > 89)
|
||||
Globals.cl.viewangles[Defines.PITCH] = 89 - pitch;
|
||||
if (Globals.cl.viewangles[Defines.PITCH] + pitch < -89)
|
||||
Globals.cl.viewangles[Defines.PITCH] = -89 - pitch;
|
||||
}
|
||||
|
||||
/*
|
||||
* ============== CL_FinishMove ==============
|
||||
*/
|
||||
static void FinishMove(usercmd_t cmd) {
|
||||
int ms;
|
||||
int i;
|
||||
|
||||
//
|
||||
// figure button bits
|
||||
//
|
||||
if ((in_attack.state & 3) != 0)
|
||||
cmd.buttons |= Defines.BUTTON_ATTACK;
|
||||
in_attack.state &= ~2;
|
||||
|
||||
if ((in_use.state & 3) != 0)
|
||||
cmd.buttons |= Defines.BUTTON_USE;
|
||||
in_use.state &= ~2;
|
||||
|
||||
if (Key.anykeydown != 0 && Globals.cls.key_dest == Defines.key_game)
|
||||
cmd.buttons |= Defines.BUTTON_ANY;
|
||||
|
||||
// send milliseconds of time to apply the move
|
||||
ms = (int) (Globals.cls.frametime * 1000);
|
||||
if (ms > 250)
|
||||
ms = 100; // time was unreasonable
|
||||
cmd.msec = (byte) ms;
|
||||
|
||||
ClampPitch();
|
||||
for (i = 0; i < 3; i++)
|
||||
cmd.angles[i] = (short) Math3D.ANGLE2SHORT(Globals.cl.viewangles[i]);
|
||||
|
||||
cmd.impulse = (byte) in_impulse;
|
||||
in_impulse = 0;
|
||||
|
||||
// send the ambient light level at the player's current position
|
||||
cmd.lightlevel = (byte) Globals.cl_lightlevel.value;
|
||||
}
|
||||
|
||||
/*
|
||||
* ================= CL_CreateCmd =================
|
||||
*/
|
||||
static void CreateCmd(usercmd_t cmd) {
|
||||
//usercmd_t cmd = new usercmd_t();
|
||||
|
||||
frame_msec = Globals.sys_frame_time - old_sys_frame_time;
|
||||
if (frame_msec < 1)
|
||||
frame_msec = 1;
|
||||
if (frame_msec > 200)
|
||||
frame_msec = 200;
|
||||
|
||||
// get basic movement from keyboard
|
||||
BaseMove(cmd);
|
||||
|
||||
// allow mice or other external controllers to add to the move
|
||||
IN.Move(cmd);
|
||||
|
||||
FinishMove(cmd);
|
||||
|
||||
old_sys_frame_time = Globals.sys_frame_time;
|
||||
|
||||
//return cmd;
|
||||
}
|
||||
|
||||
/*
|
||||
* ============ CL_InitInput ============
|
||||
*/
|
||||
static void InitInput() {
|
||||
Cmd.AddCommand("centerview", IN::CenterView);
|
||||
Cmd.AddCommand("+moveup", CL_input::IN_UpDown);
|
||||
Cmd.AddCommand("-moveup", CL_input::IN_UpUp);
|
||||
Cmd.AddCommand("+movedown", CL_input::IN_DownDown);
|
||||
Cmd.AddCommand("-movedown", CL_input::IN_DownUp);
|
||||
Cmd.AddCommand("+left", CL_input::IN_LeftDown);
|
||||
Cmd.AddCommand("-left", CL_input::IN_LeftUp);
|
||||
Cmd.AddCommand("+right", CL_input::IN_RightDown);
|
||||
Cmd.AddCommand("-right", CL_input::IN_RightUp);
|
||||
Cmd.AddCommand("+forward", CL_input::IN_ForwardDown);
|
||||
Cmd.AddCommand("-forward", CL_input::IN_ForwardUp);
|
||||
Cmd.AddCommand("+back", CL_input::IN_BackDown);
|
||||
Cmd.AddCommand("-back", CL_input::IN_BackUp);
|
||||
Cmd.AddCommand("+lookup", CL_input::IN_LookupDown);
|
||||
Cmd.AddCommand("-lookup", CL_input::IN_LookupUp);
|
||||
Cmd.AddCommand("+lookdown", CL_input::IN_LookdownDown);
|
||||
Cmd.AddCommand("-lookdown", CL_input::IN_LookdownUp);
|
||||
Cmd.AddCommand("+strafe", CL_input::IN_StrafeDown);
|
||||
Cmd.AddCommand("-strafe", CL_input::IN_StrafeUp);
|
||||
Cmd.AddCommand("+moveleft", CL_input::IN_MoveleftDown);
|
||||
Cmd.AddCommand("-moveleft", CL_input::IN_MoveleftUp);
|
||||
Cmd.AddCommand("+moveright", CL_input::IN_MoverightDown);
|
||||
Cmd.AddCommand("-moveright", CL_input::IN_MoverightUp);
|
||||
Cmd.AddCommand("+speed", CL_input::IN_SpeedDown);
|
||||
Cmd.AddCommand("-speed", CL_input::IN_SpeedUp);
|
||||
Cmd.AddCommand("+attack", CL_input::IN_AttackDown);
|
||||
Cmd.AddCommand("-attack", CL_input::IN_AttackUp);
|
||||
Cmd.AddCommand("+use", CL_input::IN_UseDown);
|
||||
Cmd.AddCommand("-use", CL_input::IN_UseUp);
|
||||
Cmd.AddCommand("impulse", CL_input::IN_Impulse);
|
||||
Cmd.AddCommand("+klook", CL_input::IN_KLookDown);
|
||||
Cmd.AddCommand("-klook", CL_input::IN_KLookUp);
|
||||
|
||||
cl_nodelta = Cvar.Get("cl_nodelta", "0", 0);
|
||||
}
|
||||
|
||||
private static final sizebuf_t buf = new sizebuf_t();
|
||||
private static final byte[] data = new byte[128];
|
||||
private static final usercmd_t nullcmd = new usercmd_t();
|
||||
/*
|
||||
* ================= CL_SendCmd =================
|
||||
*/
|
||||
static void SendCmd() {
|
||||
int i;
|
||||
usercmd_t cmd, oldcmd;
|
||||
int checksumIndex;
|
||||
|
||||
// build a command even if not connected
|
||||
|
||||
// save this command off for prediction
|
||||
i = Globals.cls.netchan.outgoing_sequence & (Defines.CMD_BACKUP - 1);
|
||||
cmd = Globals.cl.cmds[i];
|
||||
Globals.cl.cmd_time[i] = (int) Globals.cls.realtime; // for netgraph
|
||||
// ping calculation
|
||||
|
||||
// fill the cmd
|
||||
CreateCmd(cmd);
|
||||
|
||||
Globals.cl.cmd.set(cmd);
|
||||
|
||||
if (Globals.cls.state == Defines.ca_disconnected || Globals.cls.state == Defines.ca_connecting)
|
||||
return;
|
||||
|
||||
if (Globals.cls.state == Defines.ca_connected) {
|
||||
if (Globals.cls.netchan.message.cursize != 0 || Globals.curtime - Globals.cls.netchan.last_sent > 1000)
|
||||
Netchan.Transmit(Globals.cls.netchan, 0, new byte[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
// send a userinfo update if needed
|
||||
if (Globals.userinfo_modified) {
|
||||
CL.FixUpGender();
|
||||
Globals.userinfo_modified = false;
|
||||
MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_userinfo);
|
||||
MSG.WriteString(Globals.cls.netchan.message, Cvar.Userinfo());
|
||||
}
|
||||
|
||||
SZ.Init(buf, data, data.length);
|
||||
|
||||
if (cmd.buttons != 0 && Globals.cl.cinematictime > 0 && !Globals.cl.attractloop
|
||||
&& Globals.cls.realtime - Globals.cl.cinematictime > 1000) { // skip
|
||||
// the
|
||||
// rest
|
||||
// of
|
||||
// the
|
||||
// cinematic
|
||||
SCR.FinishCinematic();
|
||||
}
|
||||
|
||||
// begin a client move command
|
||||
MSG.WriteByte(buf, Defines.clc_move);
|
||||
|
||||
// save the position for a checksum byte
|
||||
checksumIndex = buf.cursize;
|
||||
MSG.WriteByte(buf, 0);
|
||||
|
||||
// let the server know what the last frame we
|
||||
// got was, so the next message can be delta compressed
|
||||
if (cl_nodelta.value != 0.0f || !Globals.cl.frame.valid || Globals.cls.demowaiting)
|
||||
MSG.WriteLong(buf, -1); // no compression
|
||||
else
|
||||
MSG.WriteLong(buf, Globals.cl.frame.serverframe);
|
||||
|
||||
// send this and the previous cmds in the message, so
|
||||
// if the last packet was dropped, it can be recovered
|
||||
i = (Globals.cls.netchan.outgoing_sequence - 2) & (Defines.CMD_BACKUP - 1);
|
||||
cmd = Globals.cl.cmds[i];
|
||||
//memset (nullcmd, 0, sizeof(nullcmd));
|
||||
nullcmd.clear();
|
||||
|
||||
MSG.WriteDeltaUsercmd(buf, nullcmd, cmd);
|
||||
oldcmd = cmd;
|
||||
|
||||
i = (Globals.cls.netchan.outgoing_sequence - 1) & (Defines.CMD_BACKUP - 1);
|
||||
cmd = Globals.cl.cmds[i];
|
||||
|
||||
MSG.WriteDeltaUsercmd(buf, oldcmd, cmd);
|
||||
oldcmd = cmd;
|
||||
|
||||
i = (Globals.cls.netchan.outgoing_sequence) & (Defines.CMD_BACKUP - 1);
|
||||
cmd = Globals.cl.cmds[i];
|
||||
|
||||
MSG.WriteDeltaUsercmd(buf, oldcmd, cmd);
|
||||
|
||||
// calculate a checksum over the move commands
|
||||
buf.data[checksumIndex] = Com.BlockSequenceCRCByte(buf.data, checksumIndex + 1, buf.cursize - checksumIndex - 1,
|
||||
Globals.cls.netchan.outgoing_sequence);
|
||||
|
||||
//
|
||||
// deliver the message
|
||||
//
|
||||
Netchan.Transmit(Globals.cls.netchan, buf.cursize, buf.data);
|
||||
}
|
||||
}
|
||||
137
src/main/java/lwjake2/client/CL_inv.java
Normal file
137
src/main/java/lwjake2/client/CL_inv.java
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.qcommon.MSG;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Vargs;
|
||||
|
||||
/**
|
||||
* CL_inv
|
||||
*/
|
||||
public class CL_inv {
|
||||
|
||||
/*
|
||||
* ================ CL_ParseInventory ================
|
||||
*/
|
||||
static void ParseInventory() {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < Defines.MAX_ITEMS; i++)
|
||||
Globals.cl.inventory[i] = MSG.ReadShort(Globals.net_message);
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ Inv_DrawString ================
|
||||
*/
|
||||
static void Inv_DrawString(int x, int y, String string) {
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
Globals.re.DrawChar(x, y, string.charAt(i));
|
||||
x += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static String getHighBitString(String s) {
|
||||
byte[] b = Lib.stringToBytes(s);
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
b[i] = (byte) (b[i] | 128);
|
||||
}
|
||||
return Lib.bytesToString(b);
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ CL_DrawInventory ================
|
||||
*/
|
||||
static final int DISPLAY_ITEMS = 17;
|
||||
|
||||
static void DrawInventory() {
|
||||
int i, j;
|
||||
int num, selected_num, item;
|
||||
int[] index = new int[Defines.MAX_ITEMS];
|
||||
String string;
|
||||
int x, y;
|
||||
String binding;
|
||||
String bind;
|
||||
int selected;
|
||||
int top;
|
||||
|
||||
selected = Globals.cl.frame.playerstate.stats[Defines.STAT_SELECTED_ITEM];
|
||||
|
||||
num = 0;
|
||||
selected_num = 0;
|
||||
for (i = 0; i < Defines.MAX_ITEMS; i++) {
|
||||
if (i == selected)
|
||||
selected_num = num;
|
||||
if (Globals.cl.inventory[i] != 0) {
|
||||
index[num] = i;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
// determine scroll point
|
||||
top = selected_num - DISPLAY_ITEMS / 2;
|
||||
if (num - top < DISPLAY_ITEMS)
|
||||
top = num - DISPLAY_ITEMS;
|
||||
if (top < 0)
|
||||
top = 0;
|
||||
|
||||
x = (Globals.viddef.width - 256) / 2;
|
||||
y = (Globals.viddef.height - 240) / 2;
|
||||
|
||||
// repaint everything next frame
|
||||
SCR.DirtyScreen();
|
||||
|
||||
Globals.re.DrawPic(x, y + 8, "inventory");
|
||||
|
||||
y += 24;
|
||||
x += 24;
|
||||
Inv_DrawString(x, y, "hotkey ### item");
|
||||
Inv_DrawString(x, y + 8, "------ --- ----");
|
||||
y += 16;
|
||||
for (i = top; i < num && i < top + DISPLAY_ITEMS; i++) {
|
||||
item = index[i];
|
||||
// search for a binding
|
||||
//Com_sprintf (binding, sizeof(binding), "use %s",
|
||||
// cl.configstrings[CS_ITEMS+item]);
|
||||
binding = "use " + Globals.cl.configstrings[Defines.CS_ITEMS + item];
|
||||
bind = "";
|
||||
for (j = 0; j < 256; j++)
|
||||
if (Globals.keybindings[j] != null && Globals.keybindings[j].equals(binding)) {
|
||||
bind = Key.KeynumToString(j);
|
||||
break;
|
||||
}
|
||||
|
||||
string = Com.sprintf("%6s %3i %s", new Vargs(3).add(bind).add(Globals.cl.inventory[item]).add(
|
||||
Globals.cl.configstrings[Defines.CS_ITEMS + item]));
|
||||
if (item != selected)
|
||||
string = getHighBitString(string);
|
||||
else // draw a blinky cursor by the selected item
|
||||
{
|
||||
if (((int) (Globals.cls.realtime * 10) & 1) != 0)
|
||||
Globals.re.DrawChar(x - 8, y, 15);
|
||||
}
|
||||
Inv_DrawString(x, y, string);
|
||||
y += 8;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
829
src/main/java/lwjake2/client/CL_newfx.java
Normal file
829
src/main/java/lwjake2/client/CL_newfx.java
Normal file
@@ -0,0 +1,829 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
/**
|
||||
* CL_newfx
|
||||
*/
|
||||
public class CL_newfx {
|
||||
|
||||
static void Flashlight(int ent, float[] pos) {
|
||||
CL_fx.cdlight_t dl;
|
||||
|
||||
dl = CL_fx.AllocDlight(ent);
|
||||
Math3D.VectorCopy(pos, dl.origin);
|
||||
dl.radius = 400;
|
||||
dl.minlight = 250;
|
||||
dl.die = Globals.cl.time + 100;
|
||||
dl.color[0] = 1;
|
||||
dl.color[1] = 1;
|
||||
dl.color[2] = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ====== CL_ColorFlash - flash of light ======
|
||||
*/
|
||||
static void ColorFlash(float[] pos, int ent, int intensity, float r,
|
||||
float g, float b) {
|
||||
CL_fx.cdlight_t dl;
|
||||
|
||||
if ((Globals.vidref_val == Defines.VIDREF_SOFT)
|
||||
&& ((r < 0) || (g < 0) || (b < 0))) {
|
||||
intensity = -intensity;
|
||||
r = -r;
|
||||
g = -g;
|
||||
b = -b;
|
||||
}
|
||||
|
||||
dl = CL_fx.AllocDlight(ent);
|
||||
Math3D.VectorCopy(pos, dl.origin);
|
||||
dl.radius = intensity;
|
||||
dl.minlight = 250;
|
||||
dl.die = Globals.cl.time + 100;
|
||||
dl.color[0] = r;
|
||||
dl.color[1] = g;
|
||||
dl.color[2] = b;
|
||||
}
|
||||
|
||||
// stack variable
|
||||
private static final float[] move = {0, 0, 0};
|
||||
private static final float[] vec = {0, 0, 0};
|
||||
private static final float[] right = {0, 0, 0};
|
||||
private static final float[] up = {0, 0, 0};
|
||||
/*
|
||||
* ====== CL_DebugTrail ======
|
||||
*/
|
||||
static void DebugTrail(float[] start, float[] end) {
|
||||
float len;
|
||||
// int j;
|
||||
cparticle_t p;
|
||||
float dec;
|
||||
// int i;
|
||||
// float d, c, s;
|
||||
// float[] dir;
|
||||
|
||||
Math3D.VectorCopy(start, move);
|
||||
Math3D.VectorSubtract(end, start, vec);
|
||||
len = Math3D.VectorNormalize(vec);
|
||||
|
||||
Math3D.MakeNormalVectors(vec, right, up);
|
||||
|
||||
// VectorScale(vec, RT2_SKIP, vec);
|
||||
|
||||
// dec = 1.0;
|
||||
// dec = 0.75;
|
||||
dec = 3;
|
||||
Math3D.VectorScale(vec, dec, vec);
|
||||
Math3D.VectorCopy(start, move);
|
||||
|
||||
while (len > 0) {
|
||||
len -= dec;
|
||||
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
Math3D.VectorClear(p.accel);
|
||||
Math3D.VectorClear(p.vel);
|
||||
p.alpha = 1.0f;
|
||||
p.alphavel = -0.1f;
|
||||
// p.alphavel = 0;
|
||||
p.color = 0x74 + (Lib.rand() & 7);
|
||||
Math3D.VectorCopy(move, p.org);
|
||||
/*
|
||||
* for (j=0 ; j <3 ; j++) { p.org[j] = move[j] + crand()*2; p.vel[j] =
|
||||
* crand()*3; p.accel[j] = 0; }
|
||||
*/
|
||||
Math3D.VectorAdd(move, vec, move);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// stack variable
|
||||
// move, vec
|
||||
static void ForceWall(float[] start, float[] end, int color) {
|
||||
float len;
|
||||
int j;
|
||||
cparticle_t p;
|
||||
|
||||
Math3D.VectorCopy(start, move);
|
||||
Math3D.VectorSubtract(end, start, vec);
|
||||
len = Math3D.VectorNormalize(vec);
|
||||
|
||||
Math3D.VectorScale(vec, 4, vec);
|
||||
|
||||
// FIXME: this is a really silly way to have a loop
|
||||
while (len > 0) {
|
||||
len -= 4;
|
||||
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
|
||||
if (Globals.rnd.nextFloat() > 0.3) {
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
Math3D.VectorClear(p.accel);
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
|
||||
p.alpha = 1.0f;
|
||||
p.alphavel = -1.0f / (3.0f + Globals.rnd.nextFloat() * 0.5f);
|
||||
p.color = color;
|
||||
for (j = 0; j < 3; j++) {
|
||||
p.org[j] = move[j] + Lib.crand() * 3;
|
||||
p.accel[j] = 0;
|
||||
}
|
||||
p.vel[0] = 0;
|
||||
p.vel[1] = 0;
|
||||
p.vel[2] = -40 - (Lib.crand() * 10);
|
||||
}
|
||||
|
||||
Math3D.VectorAdd(move, vec, move);
|
||||
}
|
||||
}
|
||||
|
||||
// stack variable
|
||||
// move, vec
|
||||
/*
|
||||
* =============== CL_BubbleTrail2 (lets you control the # of bubbles by
|
||||
* setting the distance between the spawns)
|
||||
*
|
||||
* ===============
|
||||
*/
|
||||
static void BubbleTrail2(float[] start, float[] end, int dist) {
|
||||
float len;
|
||||
int i, j;
|
||||
cparticle_t p;
|
||||
float dec;
|
||||
|
||||
Math3D.VectorCopy(start, move);
|
||||
Math3D.VectorSubtract(end, start, vec);
|
||||
len = Math3D.VectorNormalize(vec);
|
||||
|
||||
dec = dist;
|
||||
Math3D.VectorScale(vec, dec, vec);
|
||||
|
||||
for (i = 0; i < len; i += dec) {
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
|
||||
Math3D.VectorClear(p.accel);
|
||||
p.time = Globals.cl.time;
|
||||
|
||||
p.alpha = 1.0f;
|
||||
p.alphavel = -1.0f / (1 + Globals.rnd.nextFloat() * 0.1f);
|
||||
p.color = 4 + (Lib.rand() & 7);
|
||||
for (j = 0; j < 3; j++) {
|
||||
p.org[j] = move[j] + Lib.crand() * 2;
|
||||
p.vel[j] = Lib.crand() * 10;
|
||||
}
|
||||
p.org[2] -= 4;
|
||||
// p.vel[2] += 6;
|
||||
p.vel[2] += 20;
|
||||
|
||||
Math3D.VectorAdd(move, vec, move);
|
||||
}
|
||||
}
|
||||
|
||||
// stack variable
|
||||
// move, vec, right, up
|
||||
private static final float[] dir = {0, 0, 0};
|
||||
private static final float[] end = {0, 0, 0};
|
||||
|
||||
static void Heatbeam(float[] start, float[] forward) {
|
||||
float len;
|
||||
int j;
|
||||
cparticle_t p;
|
||||
int i;
|
||||
float c, s;
|
||||
float ltime;
|
||||
float step = 32.0f, rstep;
|
||||
float start_pt;
|
||||
float rot;
|
||||
float variance;
|
||||
|
||||
Math3D.VectorMA(start, 4096, forward, end);
|
||||
|
||||
Math3D.VectorCopy(start, move);
|
||||
Math3D.VectorSubtract(end, start, vec);
|
||||
len = Math3D.VectorNormalize(vec);
|
||||
|
||||
// FIXME - pmm - these might end up using old values?
|
||||
// MakeNormalVectors (vec, right, up);
|
||||
Math3D.VectorCopy(Globals.cl.v_right, right);
|
||||
Math3D.VectorCopy(Globals.cl.v_up, up);
|
||||
if (Globals.vidref_val == Defines.VIDREF_GL) { // GL mode
|
||||
Math3D.VectorMA(move, -0.5f, right, move);
|
||||
Math3D.VectorMA(move, -0.5f, up, move);
|
||||
}
|
||||
// otherwise assume SOFT
|
||||
|
||||
ltime = (float) Globals.cl.time / 1000.0f;
|
||||
start_pt = ltime * 96.0f % step;
|
||||
Math3D.VectorMA(move, start_pt, vec, move);
|
||||
|
||||
Math3D.VectorScale(vec, step, vec);
|
||||
|
||||
// Com_Printf ("%f\n", ltime);
|
||||
rstep = (float) (Math.PI / 10.0);
|
||||
float M_PI2 = (float) (Math.PI * 2.0);
|
||||
for (i = (int) start_pt; i < len; i += step) {
|
||||
if (i > step * 5) // don't bother after the 5th ring
|
||||
break;
|
||||
|
||||
for (rot = 0; rot < M_PI2; rot += rstep) {
|
||||
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
Math3D.VectorClear(p.accel);
|
||||
// rot+= fmod(ltime, 12.0)*M_PI;
|
||||
// c = cos(rot)/2.0;
|
||||
// s = sin(rot)/2.0;
|
||||
// variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2;
|
||||
variance = 0.5f;
|
||||
c = (float) (Math.cos(rot) * variance);
|
||||
s = (float) (Math.sin(rot) * variance);
|
||||
|
||||
// trim it so it looks like it's starting at the origin
|
||||
if (i < 10) {
|
||||
Math3D.VectorScale(right, c * (i / 10.0f), dir);
|
||||
Math3D.VectorMA(dir, s * (i / 10.0f), up, dir);
|
||||
} else {
|
||||
Math3D.VectorScale(right, c, dir);
|
||||
Math3D.VectorMA(dir, s, up, dir);
|
||||
}
|
||||
|
||||
p.alpha = 0.5f;
|
||||
// p.alphavel = -1.0 / (1+frand()*0.2);
|
||||
p.alphavel = -1000.0f;
|
||||
// p.color = 0x74 + (rand()&7);
|
||||
p.color = 223 - (Lib.rand() & 7);
|
||||
for (j = 0; j < 3; j++) {
|
||||
p.org[j] = move[j] + dir[j] * 3;
|
||||
// p.vel[j] = dir[j]*6;
|
||||
p.vel[j] = 0;
|
||||
}
|
||||
}
|
||||
Math3D.VectorAdd(move, vec, move);
|
||||
}
|
||||
}
|
||||
|
||||
// stack variable
|
||||
private static final float[] r = {0, 0, 0};
|
||||
private static final float[] u = {0, 0, 0};
|
||||
/*
|
||||
* =============== CL_ParticleSteamEffect
|
||||
*
|
||||
* Puffs with velocity along direction, with some randomness thrown in
|
||||
* ===============
|
||||
*/
|
||||
static void ParticleSteamEffect(float[] org, float[] dir, int color,
|
||||
int count, int magnitude) {
|
||||
int i, j;
|
||||
cparticle_t p;
|
||||
float d;
|
||||
|
||||
// vectoangles2 (dir, angle_dir);
|
||||
// AngleVectors (angle_dir, f, r, u);
|
||||
|
||||
Math3D.MakeNormalVectors(dir, r, u);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
p.color = color + (Lib.rand() & 7);
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
p.org[j] = org[j] + magnitude * 0.1f * Lib.crand();
|
||||
// p.vel[j] = dir[j]*magnitude;
|
||||
}
|
||||
Math3D.VectorScale(dir, magnitude, p.vel);
|
||||
d = Lib.crand() * magnitude / 3;
|
||||
Math3D.VectorMA(p.vel, d, r, p.vel);
|
||||
d = Lib.crand() * magnitude / 3;
|
||||
Math3D.VectorMA(p.vel, d, u, p.vel);
|
||||
|
||||
p.accel[0] = p.accel[1] = 0;
|
||||
p.accel[2] = -CL_fx.PARTICLE_GRAVITY / 2;
|
||||
p.alpha = 1.0f;
|
||||
|
||||
p.alphavel = -1.0f / (0.5f + Globals.rnd.nextFloat() * 0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
// stack variable
|
||||
// r, u, dir
|
||||
static void ParticleSteamEffect2(cl_sustain_t self)
|
||||
// float[] org, float[] dir, int color, int count, int magnitude)
|
||||
{
|
||||
int i, j;
|
||||
cparticle_t p;
|
||||
float d;
|
||||
|
||||
// vectoangles2 (dir, angle_dir);
|
||||
// AngleVectors (angle_dir, f, r, u);
|
||||
|
||||
Math3D.VectorCopy(self.dir, dir);
|
||||
Math3D.MakeNormalVectors(dir, r, u);
|
||||
|
||||
for (i = 0; i < self.count; i++) {
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
p.color = self.color + (Lib.rand() & 7);
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
p.org[j] = self.org[j] + self.magnitude * 0.1f * Lib.crand();
|
||||
// p.vel[j] = dir[j]*magnitude;
|
||||
}
|
||||
Math3D.VectorScale(dir, self.magnitude, p.vel);
|
||||
d = Lib.crand() * self.magnitude / 3;
|
||||
Math3D.VectorMA(p.vel, d, r, p.vel);
|
||||
d = Lib.crand() * self.magnitude / 3;
|
||||
Math3D.VectorMA(p.vel, d, u, p.vel);
|
||||
|
||||
p.accel[0] = p.accel[1] = 0;
|
||||
p.accel[2] = -CL_fx.PARTICLE_GRAVITY / 2;
|
||||
p.alpha = 1.0f;
|
||||
|
||||
p.alphavel = -1.0f / (0.5f + Globals.rnd.nextFloat() * 0.3f);
|
||||
}
|
||||
self.nextthink += self.thinkinterval;
|
||||
}
|
||||
|
||||
// stack variable
|
||||
// move, vec, right, up
|
||||
private static final float[] forward = {0, 0, 0};
|
||||
private static final float[] angle_dir = {0, 0, 0};
|
||||
/*
|
||||
* =============== CL_TrackerTrail ===============
|
||||
*/
|
||||
static void TrackerTrail(float[] start, float[] end, int particleColor) {
|
||||
float len;
|
||||
cparticle_t p;
|
||||
int dec;
|
||||
float dist;
|
||||
|
||||
Math3D.VectorCopy(start, move);
|
||||
Math3D.VectorSubtract(end, start, vec);
|
||||
len = Math3D.VectorNormalize(vec);
|
||||
|
||||
Math3D.VectorCopy(vec, forward);
|
||||
Math3D.vectoangles(forward, angle_dir);
|
||||
Math3D.AngleVectors(angle_dir, forward, right, up);
|
||||
|
||||
dec = 3;
|
||||
Math3D.VectorScale(vec, 3, vec);
|
||||
|
||||
// FIXME: this is a really silly way to have a loop
|
||||
while (len > 0) {
|
||||
len -= dec;
|
||||
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
Math3D.VectorClear(p.accel);
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
|
||||
p.alpha = 1.0f;
|
||||
p.alphavel = -2.0f;
|
||||
p.color = particleColor;
|
||||
dist = Math3D.DotProduct(move, forward);
|
||||
Math3D.VectorMA(move, (float) (8 * Math.cos(dist)), up, p.org);
|
||||
for (int j = 0; j < 3; j++) {
|
||||
p.vel[j] = 0;
|
||||
p.accel[j] = 0;
|
||||
}
|
||||
p.vel[2] = 5;
|
||||
|
||||
Math3D.VectorAdd(move, vec, move);
|
||||
}
|
||||
}
|
||||
|
||||
// stack variable
|
||||
// dir
|
||||
static void Tracker_Shell(float[] origin) {
|
||||
cparticle_t p;
|
||||
|
||||
for (int i = 0; i < 300; i++) {
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
Math3D.VectorClear(p.accel);
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
|
||||
p.alpha = 1.0f;
|
||||
p.alphavel = CL_fx.INSTANT_PARTICLE;
|
||||
p.color = 0;
|
||||
|
||||
dir[0] = Lib.crand();
|
||||
dir[1] = Lib.crand();
|
||||
dir[2] = Lib.crand();
|
||||
Math3D.VectorNormalize(dir);
|
||||
|
||||
Math3D.VectorMA(origin, 40, dir, p.org);
|
||||
}
|
||||
}
|
||||
|
||||
// stack variable
|
||||
// dir
|
||||
static void MonsterPlasma_Shell(float[] origin) {
|
||||
cparticle_t p;
|
||||
|
||||
for (int i = 0; i < 40; i++) {
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
Math3D.VectorClear(p.accel);
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
|
||||
p.alpha = 1.0f;
|
||||
p.alphavel = CL_fx.INSTANT_PARTICLE;
|
||||
p.color = 0xe0;
|
||||
|
||||
dir[0] = Lib.crand();
|
||||
dir[1] = Lib.crand();
|
||||
dir[2] = Lib.crand();
|
||||
Math3D.VectorNormalize(dir);
|
||||
|
||||
Math3D.VectorMA(origin, 10, dir, p.org);
|
||||
// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))),
|
||||
// dir, p.org);
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] wb_colortable = { 2 * 8, 13 * 8, 21 * 8, 18 * 8 };
|
||||
|
||||
// stack variable
|
||||
// dir
|
||||
static void Widowbeamout(cl_sustain_t self) {
|
||||
int i;
|
||||
cparticle_t p;
|
||||
|
||||
float ratio;
|
||||
|
||||
ratio = 1.0f - (((float) self.endtime - (float) Globals.cl.time) / 2100.0f);
|
||||
|
||||
for (i = 0; i < 300; i++) {
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
Math3D.VectorClear(p.accel);
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
|
||||
p.alpha = 1.0f;
|
||||
p.alphavel = CL_fx.INSTANT_PARTICLE;
|
||||
p.color = wb_colortable[Lib.rand() & 3];
|
||||
|
||||
dir[0] = Lib.crand();
|
||||
dir[1] = Lib.crand();
|
||||
dir[2] = Lib.crand();
|
||||
Math3D.VectorNormalize(dir);
|
||||
|
||||
Math3D.VectorMA(self.org, (45.0f * ratio), dir, p.org);
|
||||
// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))),
|
||||
// dir, p.org);
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] nb_colortable = { 110, 112, 114, 116 };
|
||||
|
||||
// stack variable
|
||||
// dir
|
||||
static void Nukeblast(cl_sustain_t self) {
|
||||
int i;
|
||||
cparticle_t p;
|
||||
|
||||
float ratio;
|
||||
|
||||
ratio = 1.0f - (((float) self.endtime - (float) Globals.cl.time) / 1000.0f);
|
||||
|
||||
for (i = 0; i < 700; i++) {
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
Math3D.VectorClear(p.accel);
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
|
||||
p.alpha = 1.0f;
|
||||
p.alphavel = CL_fx.INSTANT_PARTICLE;
|
||||
p.color = nb_colortable[Lib.rand() & 3];
|
||||
|
||||
dir[0] = Lib.crand();
|
||||
dir[1] = Lib.crand();
|
||||
dir[2] = Lib.crand();
|
||||
Math3D.VectorNormalize(dir);
|
||||
|
||||
Math3D.VectorMA(self.org, (200.0f * ratio), dir, p.org);
|
||||
// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))),
|
||||
// dir, p.org);
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] ws_colortable = { 2 * 8, 13 * 8, 21 * 8, 18 * 8 };
|
||||
|
||||
// stack variable
|
||||
// dir
|
||||
static void WidowSplash(float[] org) {
|
||||
int i;
|
||||
cparticle_t p;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
p.color = ws_colortable[Lib.rand() & 3];
|
||||
|
||||
dir[0] = Lib.crand();
|
||||
dir[1] = Lib.crand();
|
||||
dir[2] = Lib.crand();
|
||||
Math3D.VectorNormalize(dir);
|
||||
Math3D.VectorMA(org, 45.0f, dir, p.org);
|
||||
Math3D.VectorMA(Globals.vec3_origin, 40.0f, dir, p.vel);
|
||||
|
||||
p.accel[0] = p.accel[1] = 0;
|
||||
p.alpha = 1.0f;
|
||||
|
||||
p.alphavel = -0.8f / (0.5f + Globals.rnd.nextFloat() * 0.3f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// stack variable
|
||||
// move, vec
|
||||
/*
|
||||
* ===============
|
||||
* CL_TagTrail
|
||||
* ===============
|
||||
*/
|
||||
static void TagTrail(float[] start, float[] end, float color) {
|
||||
float len;
|
||||
int j;
|
||||
cparticle_t p;
|
||||
int dec;
|
||||
|
||||
Math3D.VectorCopy(start, move);
|
||||
Math3D.VectorSubtract(end, start, vec);
|
||||
len = Math3D.VectorNormalize(vec);
|
||||
|
||||
dec = 5;
|
||||
Math3D.VectorScale(vec, 5, vec);
|
||||
|
||||
while (len >= 0) {
|
||||
len -= dec;
|
||||
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
Math3D.VectorClear(p.accel);
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
|
||||
p.alpha = 1.0f;
|
||||
p.alphavel = -1.0f / (0.8f + Globals.rnd.nextFloat() * 0.2f);
|
||||
p.color = color;
|
||||
for (j = 0; j < 3; j++) {
|
||||
p.org[j] = move[j] + Lib.crand() * 16;
|
||||
p.vel[j] = Lib.crand() * 5;
|
||||
p.accel[j] = 0;
|
||||
}
|
||||
|
||||
Math3D.VectorAdd(move, vec, move);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* =============== CL_ColorExplosionParticles ===============
|
||||
*/
|
||||
static void ColorExplosionParticles(float[] org, int color, int run) {
|
||||
int i, j;
|
||||
cparticle_t p;
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
p.color = color + (Lib.rand() % run);
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
p.org[j] = org[j] + ((Lib.rand() % 32) - 16);
|
||||
p.vel[j] = (Lib.rand() % 256) - 128;
|
||||
}
|
||||
|
||||
p.accel[0] = p.accel[1] = 0;
|
||||
p.accel[2] = -CL_fx.PARTICLE_GRAVITY;
|
||||
p.alpha = 1.0f;
|
||||
|
||||
p.alphavel = -0.4f / (0.6f + Globals.rnd.nextFloat() * 0.2f);
|
||||
}
|
||||
}
|
||||
|
||||
// stack variable
|
||||
// r, u
|
||||
/*
|
||||
* =============== CL_ParticleSmokeEffect - like the steam effect, but
|
||||
* unaffected by gravity ===============
|
||||
*/
|
||||
static void ParticleSmokeEffect(float[] org, float[] dir, int color,
|
||||
int count, int magnitude) {
|
||||
int i, j;
|
||||
cparticle_t p;
|
||||
float d;
|
||||
|
||||
Math3D.MakeNormalVectors(dir, r, u);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
p.color = color + (Lib.rand() & 7);
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
p.org[j] = org[j] + magnitude * 0.1f * Lib.crand();
|
||||
// p.vel[j] = dir[j]*magnitude;
|
||||
}
|
||||
Math3D.VectorScale(dir, magnitude, p.vel);
|
||||
d = Lib.crand() * magnitude / 3;
|
||||
Math3D.VectorMA(p.vel, d, r, p.vel);
|
||||
d = Lib.crand() * magnitude / 3;
|
||||
Math3D.VectorMA(p.vel, d, u, p.vel);
|
||||
|
||||
p.accel[0] = p.accel[1] = p.accel[2] = 0;
|
||||
p.alpha = 1.0f;
|
||||
|
||||
p.alphavel = -1.0f / (0.5f + Globals.rnd.nextFloat() * 0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* =============== CL_BlasterParticles2
|
||||
*
|
||||
* Wall impact puffs (Green) ===============
|
||||
*/
|
||||
static void BlasterParticles2(float[] org, float[] dir, long color) {
|
||||
int i, j;
|
||||
cparticle_t p;
|
||||
float d;
|
||||
int count;
|
||||
|
||||
count = 40;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
p.color = color + (Lib.rand() & 7);
|
||||
|
||||
d = Lib.rand() & 15;
|
||||
for (j = 0; j < 3; j++) {
|
||||
p.org[j] = org[j] + ((Lib.rand() & 7) - 4) + d * dir[j];
|
||||
p.vel[j] = dir[j] * 30 + Lib.crand() * 40;
|
||||
}
|
||||
|
||||
p.accel[0] = p.accel[1] = 0;
|
||||
p.accel[2] = -CL_fx.PARTICLE_GRAVITY;
|
||||
p.alpha = 1.0f;
|
||||
|
||||
p.alphavel = -1.0f / (0.5f + Globals.rnd.nextFloat() * 0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
// stack variable
|
||||
// move, vec
|
||||
/*
|
||||
* =============== CL_BlasterTrail2
|
||||
*
|
||||
* Green! ===============
|
||||
*/
|
||||
static void BlasterTrail2(float[] start, float[] end) {
|
||||
float len;
|
||||
int j;
|
||||
cparticle_t p;
|
||||
int dec;
|
||||
|
||||
Math3D.VectorCopy(start, move);
|
||||
Math3D.VectorSubtract(end, start, vec);
|
||||
len = Math3D.VectorNormalize(vec);
|
||||
|
||||
dec = 5;
|
||||
Math3D.VectorScale(vec, 5, vec);
|
||||
|
||||
// FIXME: this is a really silly way to have a loop
|
||||
while (len > 0) {
|
||||
len -= dec;
|
||||
|
||||
if (CL_fx.free_particles == null)
|
||||
return;
|
||||
p = CL_fx.free_particles;
|
||||
CL_fx.free_particles = p.next;
|
||||
p.next = CL_fx.active_particles;
|
||||
CL_fx.active_particles = p;
|
||||
Math3D.VectorClear(p.accel);
|
||||
|
||||
p.time = Globals.cl.time;
|
||||
|
||||
p.alpha = 1.0f;
|
||||
p.alphavel = -1.0f / (0.3f + Globals.rnd.nextFloat() * 0.2f);
|
||||
p.color = 0xd0;
|
||||
for (j = 0; j < 3; j++) {
|
||||
p.org[j] = move[j] + Lib.crand();
|
||||
p.vel[j] = Lib.crand() * 5;
|
||||
p.accel[j] = 0;
|
||||
}
|
||||
|
||||
Math3D.VectorAdd(move, vec, move);
|
||||
}
|
||||
}
|
||||
}
|
||||
804
src/main/java/lwjake2/client/CL_parse.java
Normal file
804
src/main/java/lwjake2/client/CL_parse.java
Normal file
@@ -0,0 +1,804 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.game.Cmd;
|
||||
import lwjake2.game.entity_state_t;
|
||||
import lwjake2.qcommon.CM;
|
||||
import lwjake2.qcommon.Cbuf;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.qcommon.Cvar;
|
||||
import lwjake2.qcommon.FileSystem;
|
||||
import lwjake2.qcommon.BaseQ2FileSystem;
|
||||
import lwjake2.qcommon.MSG;
|
||||
import lwjake2.qcommon.SZ;
|
||||
import lwjake2.render.model_t;
|
||||
import lwjake2.sound.S;
|
||||
import lwjake2.sys.Sys;
|
||||
import lwjake2.util.Lib;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
/**
|
||||
* CL_parse
|
||||
*/
|
||||
@Slf4j
|
||||
public class CL_parse {
|
||||
private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance();
|
||||
|
||||
//// cl_parse.c -- parse a message received from the server
|
||||
|
||||
public static String svc_strings[] = { "svc_bad", "svc_muzzleflash",
|
||||
"svc_muzzlflash2", "svc_temp_entity", "svc_layout",
|
||||
"svc_inventory", "svc_nop", "svc_disconnect", "svc_reconnect",
|
||||
"svc_sound", "svc_print", "svc_stufftext", "svc_serverdata",
|
||||
"svc_configstring", "svc_spawnbaseline", "svc_centerprint",
|
||||
"svc_download", "svc_playerinfo", "svc_packetentities",
|
||||
"svc_deltapacketentities", "svc_frame" };
|
||||
|
||||
// =============================================================================
|
||||
|
||||
public static String DownloadFileName(String fn) {
|
||||
return fileSystem.getGamedir() + "/" + fn;
|
||||
}
|
||||
|
||||
/*
|
||||
* =============== CL_CheckOrDownloadFile
|
||||
*
|
||||
* Returns true if the file exists, otherwise it attempts to start a
|
||||
* download from the server. ===============
|
||||
*/
|
||||
public static boolean CheckOrDownloadFile(String filename) {
|
||||
RandomAccessFile fp;
|
||||
String name;
|
||||
|
||||
if (filename.indexOf("..") != -1) {
|
||||
Com.Printf("Refusing to download a path with ..\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fileSystem.fileLength(filename) > 0) { // it exists, no need to download
|
||||
return true;
|
||||
}
|
||||
|
||||
Globals.cls.downloadname = filename;
|
||||
|
||||
// download to a temp name, and only rename
|
||||
// to the real name when done, so if interrupted
|
||||
// a runt file wont be left
|
||||
Globals.cls.downloadtempname = Com
|
||||
.StripExtension(Globals.cls.downloadname);
|
||||
Globals.cls.downloadtempname += ".tmp";
|
||||
|
||||
// ZOID
|
||||
// check to see if we already have a tmp for this file, if so, try to
|
||||
// resume
|
||||
// open the file if not opened yet
|
||||
name = DownloadFileName(Globals.cls.downloadtempname);
|
||||
|
||||
fp = Lib.fopen(name, "r+b");
|
||||
|
||||
if (fp != null) {
|
||||
|
||||
// it exists
|
||||
long len = 0;
|
||||
|
||||
try {
|
||||
len = fp.length();
|
||||
}
|
||||
catch (IOException e) {
|
||||
}
|
||||
|
||||
|
||||
Globals.cls.download = fp;
|
||||
|
||||
// give the server an offset to start the download
|
||||
Com.Printf("Resuming " + Globals.cls.downloadname + "\n");
|
||||
MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_stringcmd);
|
||||
MSG.WriteString(Globals.cls.netchan.message, "download "
|
||||
+ Globals.cls.downloadname + " " + len);
|
||||
} else {
|
||||
Com.Printf("Downloading " + Globals.cls.downloadname + "\n");
|
||||
MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_stringcmd);
|
||||
MSG.WriteString(Globals.cls.netchan.message, "download "
|
||||
+ Globals.cls.downloadname);
|
||||
}
|
||||
|
||||
Globals.cls.downloadnumber++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* =============== CL_Download_f
|
||||
*
|
||||
* Request a download from the server ===============
|
||||
*/
|
||||
public static Runnable Download_f = () -> {
|
||||
String filename;
|
||||
|
||||
if (Cmd.Argc() != 2) {
|
||||
Com.Printf("Usage: download <filename>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
filename = Cmd.Argv(1);
|
||||
|
||||
if (filename.indexOf("..") != -1) {
|
||||
Com.Printf("Refusing to download a path with ..\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileSystem.loadFile(filename) != null) { // it exists, no need to
|
||||
// download
|
||||
Com.Printf("File already exists.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Globals.cls.downloadname = filename;
|
||||
Com.Printf("Downloading " + Globals.cls.downloadname + "\n");
|
||||
|
||||
// download to a temp name, and only rename
|
||||
// to the real name when done, so if interrupted
|
||||
// a runt file wont be left
|
||||
Globals.cls.downloadtempname = Com
|
||||
.StripExtension(Globals.cls.downloadname);
|
||||
Globals.cls.downloadtempname += ".tmp";
|
||||
|
||||
MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_stringcmd);
|
||||
MSG.WriteString(Globals.cls.netchan.message, "download "
|
||||
+ Globals.cls.downloadname);
|
||||
|
||||
Globals.cls.downloadnumber++;
|
||||
};
|
||||
|
||||
/*
|
||||
* ====================== CL_RegisterSounds ======================
|
||||
*/
|
||||
public static void RegisterSounds() {
|
||||
S.BeginRegistration();
|
||||
CL_tent.RegisterTEntSounds();
|
||||
for (int i = 1; i < Defines.MAX_SOUNDS; i++) {
|
||||
if (Globals.cl.configstrings[Defines.CS_SOUNDS + i] == null
|
||||
|| Globals.cl.configstrings[Defines.CS_SOUNDS + i]
|
||||
.equals("")
|
||||
|| Globals.cl.configstrings[Defines.CS_SOUNDS + i]
|
||||
.equals("\0"))
|
||||
break;
|
||||
Globals.cl.sound_precache[i] = S
|
||||
.RegisterSound(Globals.cl.configstrings[Defines.CS_SOUNDS
|
||||
+ i]);
|
||||
Sys.SendKeyEvents(); // pump message loop
|
||||
}
|
||||
S.EndRegistration();
|
||||
}
|
||||
|
||||
/*
|
||||
* ===================== CL_ParseDownload
|
||||
*
|
||||
* A download message has been received from the server
|
||||
* =====================
|
||||
*/
|
||||
public static void ParseDownload() {
|
||||
|
||||
// read the data
|
||||
int size = MSG.ReadShort(Globals.net_message);
|
||||
int percent = MSG.ReadByte(Globals.net_message);
|
||||
if (size == -1) {
|
||||
Com.Printf("Server does not have this file.\n");
|
||||
if (Globals.cls.download != null) {
|
||||
// if here, we tried to resume a file but the server said no
|
||||
try {
|
||||
Globals.cls.download.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
Globals.cls.download = null;
|
||||
}
|
||||
CL.RequestNextDownload();
|
||||
return;
|
||||
}
|
||||
|
||||
// open the file if not opened yet
|
||||
if (Globals.cls.download == null) {
|
||||
String name = DownloadFileName(Globals.cls.downloadtempname).toLowerCase();
|
||||
|
||||
fileSystem.createPath(name);
|
||||
|
||||
Globals.cls.download = Lib.fopen(name, "rw");
|
||||
if (Globals.cls.download == null) {
|
||||
Globals.net_message.readcount += size;
|
||||
Com.Printf("Failed to open " + Globals.cls.downloadtempname
|
||||
+ "\n");
|
||||
CL.RequestNextDownload();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//fwrite(net_message.data[net_message.readcount], 1, size,
|
||||
// cls.download);
|
||||
try {
|
||||
Globals.cls.download.write(Globals.net_message.data,
|
||||
Globals.net_message.readcount, size);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
Globals.net_message.readcount += size;
|
||||
|
||||
if (percent != 100) {
|
||||
// request next block
|
||||
// change display routines by zoid
|
||||
Globals.cls.downloadpercent = percent;
|
||||
MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_stringcmd);
|
||||
SZ.Print(Globals.cls.netchan.message, "nextdl");
|
||||
} else {
|
||||
String oldn, newn;
|
||||
//char oldn[MAX_OSPATH];
|
||||
//char newn[MAX_OSPATH];
|
||||
|
||||
// Com.Printf ("100%%\n");
|
||||
|
||||
try {
|
||||
Globals.cls.download.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
|
||||
// rename the temp file to it's final name
|
||||
oldn = DownloadFileName(Globals.cls.downloadtempname);
|
||||
newn = DownloadFileName(Globals.cls.downloadname);
|
||||
int r = Lib.rename(oldn, newn);
|
||||
if (r != 0)
|
||||
Com.Printf("failed to rename.\n");
|
||||
|
||||
Globals.cls.download = null;
|
||||
Globals.cls.downloadpercent = 0;
|
||||
|
||||
// get another file if needed
|
||||
|
||||
CL.RequestNextDownload();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* =====================================================================
|
||||
*
|
||||
* SERVER CONNECTING MESSAGES
|
||||
*
|
||||
* =====================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================== CL_ParseServerData ==================
|
||||
*/
|
||||
//checked once, was ok.
|
||||
public static void ParseServerData() {
|
||||
|
||||
String str;
|
||||
int i;
|
||||
|
||||
Com.DPrintf("ParseServerData():Serverdata packet received.\n");
|
||||
//
|
||||
// wipe the client_state_t struct
|
||||
//
|
||||
CL.ClearState();
|
||||
Globals.cls.state = Defines.ca_connected;
|
||||
|
||||
// parse protocol version number
|
||||
i = MSG.ReadLong(Globals.net_message);
|
||||
Globals.cls.serverProtocol = i;
|
||||
|
||||
// BIG HACK to let demos from release work with the 3.0x patch!!!
|
||||
if (Globals.server_state != 0) {
|
||||
} else if (i != Defines.PROTOCOL_VERSION)
|
||||
Com.Error(Defines.ERR_DROP, "Server returned version " + i
|
||||
+ ", not " + Defines.PROTOCOL_VERSION);
|
||||
|
||||
Globals.cl.servercount = MSG.ReadLong(Globals.net_message);
|
||||
Globals.cl.attractloop = MSG.ReadByte(Globals.net_message) != 0;
|
||||
|
||||
// game directory
|
||||
str = MSG.ReadString(Globals.net_message);
|
||||
Globals.cl.gamedir = str;
|
||||
Com.dprintln("gamedir=" + str);
|
||||
|
||||
// set gamedir
|
||||
if (str.length() > 0
|
||||
&& (fileSystem.getGamedirVar().string == null
|
||||
|| fileSystem.getGamedirVar().string.length() == 0 || fileSystem.getGamedirVar().string
|
||||
.equals(str))
|
||||
|| (str.length() == 0 && (fileSystem.getGamedirVar().string != null || fileSystem.getGamedirVar().string
|
||||
.length() == 0)))
|
||||
Cvar.Set("game", str);
|
||||
|
||||
// parse player entity number
|
||||
Globals.cl.playernum = MSG.ReadShort(Globals.net_message);
|
||||
Com.dprintln("numplayers=" + Globals.cl.playernum);
|
||||
// get the full level name
|
||||
str = MSG.ReadString(Globals.net_message);
|
||||
Com.dprintln("levelname=" + str);
|
||||
|
||||
if (Globals.cl.playernum == -1) { // playing a cinematic or showing a
|
||||
// pic, not a level
|
||||
SCR.PlayCinematic(str);
|
||||
} else {
|
||||
// seperate the printfs so the server message can have a color
|
||||
// Com.Printf(
|
||||
// "\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
|
||||
// Com.Printf('\02' + str + "\n");
|
||||
Com.Printf("Levelname:" + str + "\n");
|
||||
// need to prep refresh at next oportunity
|
||||
Globals.cl.refresh_prepped = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ================== CL_ParseBaseline ==================
|
||||
*/
|
||||
public static void ParseBaseline() {
|
||||
entity_state_t es;
|
||||
int newnum;
|
||||
|
||||
entity_state_t nullstate = new entity_state_t(null);
|
||||
//memset(nullstate, 0, sizeof(nullstate));
|
||||
int bits[] = { 0 };
|
||||
newnum = CL_ents.ParseEntityBits(bits);
|
||||
es = Globals.cl_entities[newnum].baseline;
|
||||
CL_ents.ParseDelta(nullstate, es, newnum, bits[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ CL_LoadClientinfo
|
||||
*
|
||||
* ================
|
||||
*/
|
||||
public static void LoadClientinfo(clientinfo_t ci, String s) {
|
||||
int i;
|
||||
int t;
|
||||
|
||||
//char model_name[MAX_QPATH];
|
||||
//char skin_name[MAX_QPATH];
|
||||
//char model_filename[MAX_QPATH];
|
||||
//char skin_filename[MAX_QPATH];
|
||||
//char weapon_filename[MAX_QPATH];
|
||||
|
||||
String model_name, skin_name, model_filename, skin_filename, weapon_filename;
|
||||
|
||||
ci.cinfo = s;
|
||||
//ci.cinfo[sizeof(ci.cinfo) - 1] = 0;
|
||||
|
||||
// isolate the player's name
|
||||
ci.name = s;
|
||||
//ci.name[sizeof(ci.name) - 1] = 0;
|
||||
|
||||
t = s.indexOf('\\');
|
||||
//t = strstr(s, "\\");
|
||||
|
||||
if (t != -1) {
|
||||
ci.name = s.substring(0, t);
|
||||
s = s.substring(t + 1, s.length());
|
||||
//s = t + 1;
|
||||
}
|
||||
|
||||
if (Globals.cl_noskins.value != 0 || s.length() == 0) {
|
||||
|
||||
model_filename = ("players/male/tris.md2");
|
||||
weapon_filename = ("players/male/weapon.md2");
|
||||
skin_filename = ("players/male/grunt.pcx");
|
||||
ci.iconname = ("/players/male/grunt_i.pcx");
|
||||
|
||||
ci.model = Globals.re.RegisterModel(model_filename);
|
||||
|
||||
ci.weaponmodel = new model_t[Defines.MAX_CLIENTWEAPONMODELS];
|
||||
ci.weaponmodel[0] = Globals.re.RegisterModel(weapon_filename);
|
||||
ci.skin = Globals.re.RegisterSkin(skin_filename);
|
||||
ci.icon = Globals.re.RegisterPic(ci.iconname);
|
||||
|
||||
} else {
|
||||
// isolate the model name
|
||||
|
||||
int pos = s.indexOf('/');
|
||||
|
||||
if (pos == -1)
|
||||
pos = s.indexOf('/');
|
||||
if (pos == -1) {
|
||||
pos = 0;
|
||||
Com.Error(Defines.ERR_FATAL, "Invalid model name:" + s);
|
||||
}
|
||||
|
||||
model_name = s.substring(0, pos);
|
||||
|
||||
// isolate the skin name
|
||||
skin_name = s.substring(pos + 1, s.length());
|
||||
|
||||
// model file
|
||||
model_filename = "players/" + model_name + "/tris.md2";
|
||||
ci.model = Globals.re.RegisterModel(model_filename);
|
||||
|
||||
if (ci.model == null) {
|
||||
model_name = "male";
|
||||
model_filename = "players/male/tris.md2";
|
||||
ci.model = Globals.re.RegisterModel(model_filename);
|
||||
}
|
||||
|
||||
// skin file
|
||||
skin_filename = "players/" + model_name + "/" + skin_name + ".pcx";
|
||||
ci.skin = Globals.re.RegisterSkin(skin_filename);
|
||||
|
||||
// if we don't have the skin and the model wasn't male,
|
||||
// see if the male has it (this is for CTF's skins)
|
||||
if (ci.skin == null && !model_name.equalsIgnoreCase("male")) {
|
||||
// change model to male
|
||||
model_name = "male";
|
||||
model_filename = "players/male/tris.md2";
|
||||
ci.model = Globals.re.RegisterModel(model_filename);
|
||||
|
||||
// see if the skin exists for the male model
|
||||
skin_filename = "players/" + model_name + "/" + skin_name
|
||||
+ ".pcx";
|
||||
ci.skin = Globals.re.RegisterSkin(skin_filename);
|
||||
}
|
||||
|
||||
// if we still don't have a skin, it means that the male model
|
||||
// didn't have
|
||||
// it, so default to grunt
|
||||
if (ci.skin == null) {
|
||||
// see if the skin exists for the male model
|
||||
skin_filename = "players/" + model_name + "/grunt.pcx";
|
||||
ci.skin = Globals.re.RegisterSkin(skin_filename);
|
||||
}
|
||||
|
||||
// weapon file
|
||||
for (i = 0; i < CL_view.num_cl_weaponmodels; i++) {
|
||||
weapon_filename = "players/" + model_name + "/"
|
||||
+ CL_view.cl_weaponmodels[i];
|
||||
ci.weaponmodel[i] = Globals.re.RegisterModel(weapon_filename);
|
||||
if (null == ci.weaponmodel[i] && model_name.equals("cyborg")) {
|
||||
// try male
|
||||
weapon_filename = "players/male/"
|
||||
+ CL_view.cl_weaponmodels[i];
|
||||
ci.weaponmodel[i] = Globals.re
|
||||
.RegisterModel(weapon_filename);
|
||||
}
|
||||
if (0 == Globals.cl_vwep.value)
|
||||
break; // only one when vwep is off
|
||||
}
|
||||
|
||||
// icon file
|
||||
ci.iconname = "/players/" + model_name + "/" + skin_name + "_i.pcx";
|
||||
ci.icon = Globals.re.RegisterPic(ci.iconname);
|
||||
}
|
||||
|
||||
// must have loaded all data types to be valud
|
||||
if (ci.skin == null || ci.icon == null || ci.model == null
|
||||
|| ci.weaponmodel[0] == null) {
|
||||
ci.skin = null;
|
||||
ci.icon = null;
|
||||
ci.model = null;
|
||||
ci.weaponmodel[0] = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ CL_ParseClientinfo
|
||||
*
|
||||
* Load the skin, icon, and model for a client ================
|
||||
*/
|
||||
public static void ParseClientinfo(int player) {
|
||||
String s;
|
||||
clientinfo_t ci;
|
||||
|
||||
s = Globals.cl.configstrings[player + Defines.CS_PLAYERSKINS];
|
||||
|
||||
ci = Globals.cl.clientinfo[player];
|
||||
|
||||
LoadClientinfo(ci, s);
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ CL_ParseConfigString ================
|
||||
*/
|
||||
public static void ParseConfigString() {
|
||||
int i;
|
||||
String s;
|
||||
String olds;
|
||||
|
||||
i = MSG.ReadShort(Globals.net_message);
|
||||
|
||||
if (i < 0 || i >= Defines.MAX_CONFIGSTRINGS)
|
||||
Com.Error(Defines.ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
|
||||
|
||||
s = MSG.ReadString(Globals.net_message);
|
||||
|
||||
olds = Globals.cl.configstrings[i];
|
||||
Globals.cl.configstrings[i] = s;
|
||||
|
||||
//Com.dprintln("ParseConfigString(): configstring[" + i + "]=<"+s+">");
|
||||
|
||||
// do something apropriate
|
||||
|
||||
if (i >= Defines.CS_LIGHTS
|
||||
&& i < Defines.CS_LIGHTS + Defines.MAX_LIGHTSTYLES) {
|
||||
|
||||
CL_fx.SetLightstyle(i - Defines.CS_LIGHTS);
|
||||
|
||||
} else if (i >= Defines.CS_MODELS && i < Defines.CS_MODELS + Defines.MAX_MODELS) {
|
||||
if (Globals.cl.refresh_prepped) {
|
||||
Globals.cl.model_draw[i - Defines.CS_MODELS] = Globals.re
|
||||
.RegisterModel(Globals.cl.configstrings[i]);
|
||||
if (Globals.cl.configstrings[i].startsWith("*"))
|
||||
Globals.cl.model_clip[i - Defines.CS_MODELS] = CM
|
||||
.InlineModel(Globals.cl.configstrings[i]);
|
||||
else
|
||||
Globals.cl.model_clip[i - Defines.CS_MODELS] = null;
|
||||
}
|
||||
} else if (i >= Defines.CS_SOUNDS
|
||||
&& i < Defines.CS_SOUNDS + Defines.MAX_MODELS) {
|
||||
if (Globals.cl.refresh_prepped)
|
||||
Globals.cl.sound_precache[i - Defines.CS_SOUNDS] = S
|
||||
.RegisterSound(Globals.cl.configstrings[i]);
|
||||
} else if (i >= Defines.CS_IMAGES
|
||||
&& i < Defines.CS_IMAGES + Defines.MAX_MODELS) {
|
||||
if (Globals.cl.refresh_prepped)
|
||||
Globals.cl.image_precache[i - Defines.CS_IMAGES] = Globals.re
|
||||
.RegisterPic(Globals.cl.configstrings[i]);
|
||||
} else if (i >= Defines.CS_PLAYERSKINS
|
||||
&& i < Defines.CS_PLAYERSKINS + Defines.MAX_CLIENTS) {
|
||||
if (Globals.cl.refresh_prepped && !olds.equals(s))
|
||||
ParseClientinfo(i - Defines.CS_PLAYERSKINS);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* =====================================================================
|
||||
*
|
||||
* ACTION MESSAGES
|
||||
*
|
||||
* =====================================================================
|
||||
*/
|
||||
|
||||
private static final float[] pos_v = { 0, 0, 0 };
|
||||
/*
|
||||
* ================== CL_ParseStartSoundPacket ==================
|
||||
*/
|
||||
public static void ParseStartSoundPacket() {
|
||||
float pos[];
|
||||
int channel, ent;
|
||||
int sound_num;
|
||||
float volume;
|
||||
float attenuation;
|
||||
int flags;
|
||||
float ofs;
|
||||
|
||||
flags = MSG.ReadByte(Globals.net_message);
|
||||
sound_num = MSG.ReadByte(Globals.net_message);
|
||||
|
||||
if ((flags & Defines.SND_VOLUME) != 0)
|
||||
volume = MSG.ReadByte(Globals.net_message) / 255.0f;
|
||||
else
|
||||
volume = Defines.DEFAULT_SOUND_PACKET_VOLUME;
|
||||
|
||||
if ((flags & Defines.SND_ATTENUATION) != 0)
|
||||
attenuation = MSG.ReadByte(Globals.net_message) / 64.0f;
|
||||
else
|
||||
attenuation = Defines.DEFAULT_SOUND_PACKET_ATTENUATION;
|
||||
|
||||
if ((flags & Defines.SND_OFFSET) != 0)
|
||||
ofs = MSG.ReadByte(Globals.net_message) / 1000.0f;
|
||||
else
|
||||
ofs = 0;
|
||||
|
||||
if ((flags & Defines.SND_ENT) != 0) { // entity reletive
|
||||
channel = MSG.ReadShort(Globals.net_message);
|
||||
ent = channel >> 3;
|
||||
if (ent > Defines.MAX_EDICTS)
|
||||
Com.Error(Defines.ERR_DROP, "CL_ParseStartSoundPacket: ent = "
|
||||
+ ent);
|
||||
|
||||
channel &= 7;
|
||||
} else {
|
||||
ent = 0;
|
||||
channel = 0;
|
||||
}
|
||||
|
||||
if ((flags & Defines.SND_POS) != 0) { // positioned in space
|
||||
MSG.ReadPos(Globals.net_message, pos_v);
|
||||
// is ok. sound driver copies
|
||||
pos = pos_v;
|
||||
} else
|
||||
// use entity number
|
||||
pos = null;
|
||||
|
||||
if (null == Globals.cl.sound_precache[sound_num])
|
||||
return;
|
||||
|
||||
S.StartSound(pos, ent, channel, Globals.cl.sound_precache[sound_num],
|
||||
volume, attenuation, ofs);
|
||||
}
|
||||
|
||||
public static void SHOWNET(String s) {
|
||||
if (Globals.cl_shownet.value >= 2)
|
||||
Com.Printf(Globals.net_message.readcount - 1 + ":" + s + "\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* ===================== CL_ParseServerMessage =====================
|
||||
*/
|
||||
public static void ParseServerMessage() {
|
||||
int cmd;
|
||||
String s;
|
||||
int i;
|
||||
|
||||
//
|
||||
// if recording demos, copy the message out
|
||||
//
|
||||
//if (cl_shownet.value == 1)
|
||||
//Com.Printf(net_message.cursize + " ");
|
||||
//else if (cl_shownet.value >= 2)
|
||||
//Com.Printf("------------------\n");
|
||||
|
||||
//
|
||||
// parse the message
|
||||
//
|
||||
while (true) {
|
||||
if (Globals.net_message.readcount > Globals.net_message.cursize) {
|
||||
Com.Error(Defines.ERR_FATAL,
|
||||
"CL_ParseServerMessage: Bad server message:");
|
||||
break;
|
||||
}
|
||||
|
||||
cmd = MSG.ReadByte(Globals.net_message);
|
||||
|
||||
if (cmd == -1) {
|
||||
SHOWNET("END OF MESSAGE");
|
||||
break;
|
||||
}
|
||||
|
||||
if (Globals.cl_shownet.value >= 2) {
|
||||
if (null == svc_strings[cmd])
|
||||
Com.Printf(Globals.net_message.readcount - 1 + ":BAD CMD "
|
||||
+ cmd + "\n");
|
||||
else
|
||||
SHOWNET(svc_strings[cmd]);
|
||||
}
|
||||
|
||||
// other commands
|
||||
switch (cmd) {
|
||||
default:
|
||||
Com.Error(Defines.ERR_DROP,
|
||||
"CL_ParseServerMessage: Illegible server message\n");
|
||||
break;
|
||||
|
||||
case Defines.svc_nop:
|
||||
// Com.Printf ("svc_nop\n");
|
||||
break;
|
||||
|
||||
case Defines.svc_disconnect:
|
||||
Com.Error(Defines.ERR_DISCONNECT, "Server disconnected\n");
|
||||
break;
|
||||
|
||||
case Defines.svc_reconnect:
|
||||
Com.Printf("Server disconnected, reconnecting\n");
|
||||
if (Globals.cls.download != null) {
|
||||
//ZOID, close download
|
||||
try {
|
||||
Globals.cls.download.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
Globals.cls.download = null;
|
||||
}
|
||||
Globals.cls.state = Defines.ca_connecting;
|
||||
Globals.cls.connect_time = -99999; // CL_CheckForResend() will
|
||||
// fire immediately
|
||||
break;
|
||||
|
||||
case Defines.svc_print:
|
||||
i = MSG.ReadByte(Globals.net_message);
|
||||
if (i == Defines.PRINT_CHAT) {
|
||||
S.StartLocalSound("misc/talk.wav");
|
||||
Globals.con.ormask = 128;
|
||||
}
|
||||
//TODO потом уброать
|
||||
String msg = MSG.ReadString(Globals.net_message);
|
||||
while (msg.startsWith("\n")) { msg = msg.substring(1); }
|
||||
while (msg.endsWith("\n")) { msg = msg.substring(0, msg.lastIndexOf("\n")); }
|
||||
while (msg.endsWith("\r")) { msg = msg.substring(0, msg.lastIndexOf("\r")); }
|
||||
msg = msg.trim();
|
||||
if (!msg.isEmpty()) {
|
||||
log.info(msg);
|
||||
}
|
||||
Globals.con.ormask = 0;
|
||||
break;
|
||||
|
||||
case Defines.svc_centerprint:
|
||||
SCR.CenterPrint(MSG.ReadString(Globals.net_message));
|
||||
break;
|
||||
|
||||
case Defines.svc_stufftext:
|
||||
s = MSG.ReadString(Globals.net_message);
|
||||
Com.DPrintf("stufftext: " + s + "\n");
|
||||
Cbuf.AddText(s);
|
||||
break;
|
||||
|
||||
case Defines.svc_serverdata:
|
||||
Cbuf.Execute(); // make sure any stuffed commands are done
|
||||
ParseServerData();
|
||||
break;
|
||||
|
||||
case Defines.svc_configstring:
|
||||
ParseConfigString();
|
||||
break;
|
||||
|
||||
case Defines.svc_sound:
|
||||
ParseStartSoundPacket();
|
||||
break;
|
||||
|
||||
case Defines.svc_spawnbaseline:
|
||||
ParseBaseline();
|
||||
break;
|
||||
|
||||
case Defines.svc_temp_entity:
|
||||
CL_tent.ParseTEnt();
|
||||
break;
|
||||
|
||||
case Defines.svc_muzzleflash:
|
||||
CL_fx.ParseMuzzleFlash();
|
||||
break;
|
||||
|
||||
case Defines.svc_muzzleflash2:
|
||||
CL_fx.ParseMuzzleFlash2();
|
||||
break;
|
||||
|
||||
case Defines.svc_download:
|
||||
ParseDownload();
|
||||
break;
|
||||
|
||||
case Defines.svc_frame:
|
||||
CL_ents.ParseFrame();
|
||||
break;
|
||||
|
||||
case Defines.svc_inventory:
|
||||
CL_inv.ParseInventory();
|
||||
break;
|
||||
|
||||
case Defines.svc_layout:
|
||||
s = MSG.ReadString(Globals.net_message);
|
||||
Globals.cl.layout = s;
|
||||
break;
|
||||
|
||||
case Defines.svc_playerinfo:
|
||||
case Defines.svc_packetentities:
|
||||
case Defines.svc_deltapacketentities:
|
||||
Com.Error(Defines.ERR_DROP, "Out of place frame data");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CL_view.AddNetgraph();
|
||||
|
||||
//
|
||||
// we don't know if it is ok to save a demo message until
|
||||
// after we have parsed the frame
|
||||
//
|
||||
if (Globals.cls.demorecording && !Globals.cls.demowaiting)
|
||||
CL.WriteDemoMessage();
|
||||
}
|
||||
}
|
||||
297
src/main/java/lwjake2/client/CL_pred.java
Normal file
297
src/main/java/lwjake2/client/CL_pred.java
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.game.cmodel_t;
|
||||
import lwjake2.game.edict_t;
|
||||
import lwjake2.game.entity_state_t;
|
||||
import lwjake2.game.pmove_t;
|
||||
import lwjake2.game.trace_t;
|
||||
import lwjake2.game.usercmd_t;
|
||||
import lwjake2.qcommon.CM;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.qcommon.PMove;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
/**
|
||||
* CL_pred
|
||||
*/
|
||||
public class CL_pred {
|
||||
|
||||
/*
|
||||
* =================== CL_CheckPredictionError ===================
|
||||
*/
|
||||
static void CheckPredictionError() {
|
||||
int frame;
|
||||
int[] delta = new int[3];
|
||||
int i;
|
||||
int len;
|
||||
|
||||
if (Globals.cl_predict.value == 0.0f
|
||||
|| (Globals.cl.frame.playerstate.pmove.pm_flags & pmove_t.PMF_NO_PREDICTION) != 0)
|
||||
return;
|
||||
|
||||
// calculate the last usercmd_t we sent that the server has processed
|
||||
frame = Globals.cls.netchan.incoming_acknowledged;
|
||||
frame &= (Defines.CMD_BACKUP - 1);
|
||||
|
||||
// compare what the server returned with what we had predicted it to be
|
||||
Math3D.VectorSubtract(Globals.cl.frame.playerstate.pmove.origin,
|
||||
Globals.cl.predicted_origins[frame], delta);
|
||||
|
||||
// save the prediction error for interpolation
|
||||
len = Math.abs(delta[0]) + Math.abs(delta[1]) + Math.abs(delta[2]);
|
||||
if (len > 640) // 80 world units
|
||||
{ // a teleport or something
|
||||
Math3D.VectorClear(Globals.cl.prediction_error);
|
||||
} else {
|
||||
if (Globals.cl_showmiss.value != 0.0f
|
||||
&& (delta[0] != 0 || delta[1] != 0 || delta[2] != 0))
|
||||
Com.Printf("prediction miss on " + Globals.cl.frame.serverframe
|
||||
+ ": " + (delta[0] + delta[1] + delta[2]) + "\n");
|
||||
|
||||
Math3D.VectorCopy(Globals.cl.frame.playerstate.pmove.origin,
|
||||
Globals.cl.predicted_origins[frame]);
|
||||
|
||||
// save for error itnerpolation
|
||||
for (i = 0; i < 3; i++)
|
||||
Globals.cl.prediction_error[i] = delta[i] * 0.125f;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ==================== CL_ClipMoveToEntities
|
||||
*
|
||||
* ====================
|
||||
*/
|
||||
static void ClipMoveToEntities(float[] start, float[] mins, float[] maxs,
|
||||
float[] end, trace_t tr) {
|
||||
int i, x, zd, zu;
|
||||
trace_t trace;
|
||||
int headnode;
|
||||
float[] angles;
|
||||
entity_state_t ent;
|
||||
int num;
|
||||
cmodel_t cmodel;
|
||||
float[] bmins = new float[3];
|
||||
float[] bmaxs = new float[3];
|
||||
|
||||
for (i = 0; i < Globals.cl.frame.num_entities; i++) {
|
||||
num = (Globals.cl.frame.parse_entities + i)
|
||||
& (Defines.MAX_PARSE_ENTITIES - 1);
|
||||
ent = Globals.cl_parse_entities[num];
|
||||
|
||||
if (ent.solid == 0)
|
||||
continue;
|
||||
|
||||
if (ent.number == Globals.cl.playernum + 1)
|
||||
continue;
|
||||
|
||||
if (ent.solid == 31) { // special value for bmodel
|
||||
cmodel = Globals.cl.model_clip[ent.modelindex];
|
||||
if (cmodel == null)
|
||||
continue;
|
||||
headnode = cmodel.headnode;
|
||||
angles = ent.angles;
|
||||
} else { // encoded bbox
|
||||
x = 8 * (ent.solid & 31);
|
||||
zd = 8 * ((ent.solid >>> 5) & 31);
|
||||
zu = 8 * ((ent.solid >>> 10) & 63) - 32;
|
||||
|
||||
bmins[0] = bmins[1] = -x;
|
||||
bmaxs[0] = bmaxs[1] = x;
|
||||
bmins[2] = -zd;
|
||||
bmaxs[2] = zu;
|
||||
|
||||
headnode = CM.HeadnodeForBox(bmins, bmaxs);
|
||||
angles = Globals.vec3_origin; // boxes don't rotate
|
||||
}
|
||||
|
||||
if (tr.allsolid)
|
||||
return;
|
||||
|
||||
trace = CM.TransformedBoxTrace(start, end, mins, maxs, headnode,
|
||||
Defines.MASK_PLAYERSOLID, ent.origin, angles);
|
||||
|
||||
if (trace.allsolid || trace.startsolid
|
||||
|| trace.fraction < tr.fraction) {
|
||||
trace.ent = ent.surrounding_ent;
|
||||
if (tr.startsolid) {
|
||||
tr.set(trace); // rst: solved the Z U P P E L - P R O B L E
|
||||
// M
|
||||
tr.startsolid = true;
|
||||
} else
|
||||
tr.set(trace); // rst: solved the Z U P P E L - P R O B L E
|
||||
// M
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ CL_PMTrace ================
|
||||
*/
|
||||
|
||||
public static edict_t DUMMY_ENT = new edict_t(-1);
|
||||
|
||||
static trace_t PMTrace(float[] start, float[] mins, float[] maxs,
|
||||
float[] end) {
|
||||
trace_t t;
|
||||
|
||||
// check against world
|
||||
t = CM.BoxTrace(start, end, mins, maxs, 0, Defines.MASK_PLAYERSOLID);
|
||||
|
||||
if (t.fraction < 1.0f) {
|
||||
t.ent = DUMMY_ENT;
|
||||
}
|
||||
|
||||
// check all other solid models
|
||||
ClipMoveToEntities(start, mins, maxs, end, t);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
* ================= PMpointcontents
|
||||
*
|
||||
* Returns the content identificator of the point. =================
|
||||
*/
|
||||
static int PMpointcontents(float[] point) {
|
||||
int i;
|
||||
entity_state_t ent;
|
||||
int num;
|
||||
cmodel_t cmodel;
|
||||
int contents;
|
||||
|
||||
contents = CM.PointContents(point, 0);
|
||||
|
||||
for (i = 0; i < Globals.cl.frame.num_entities; i++) {
|
||||
num = (Globals.cl.frame.parse_entities + i)
|
||||
& (Defines.MAX_PARSE_ENTITIES - 1);
|
||||
ent = Globals.cl_parse_entities[num];
|
||||
|
||||
if (ent.solid != 31) // special value for bmodel
|
||||
continue;
|
||||
|
||||
cmodel = Globals.cl.model_clip[ent.modelindex];
|
||||
if (cmodel == null)
|
||||
continue;
|
||||
|
||||
contents |= CM.TransformedPointContents(point, cmodel.headnode,
|
||||
ent.origin, ent.angles);
|
||||
}
|
||||
return contents;
|
||||
}
|
||||
|
||||
/*
|
||||
* ================= CL_PredictMovement
|
||||
*
|
||||
* Sets cl.predicted_origin and cl.predicted_angles =================
|
||||
*/
|
||||
static void PredictMovement() {
|
||||
|
||||
if (Globals.cls.state != Defines.ca_active)
|
||||
return;
|
||||
|
||||
if (Globals.cl_paused.value != 0.0f)
|
||||
return;
|
||||
|
||||
if (Globals.cl_predict.value == 0.0f
|
||||
|| (Globals.cl.frame.playerstate.pmove.pm_flags & pmove_t.PMF_NO_PREDICTION) != 0) {
|
||||
// just set angles
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Globals.cl.predicted_angles[i] = Globals.cl.viewangles[i]
|
||||
+ Math3D
|
||||
.SHORT2ANGLE(Globals.cl.frame.playerstate.pmove.delta_angles[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int ack = Globals.cls.netchan.incoming_acknowledged;
|
||||
int current = Globals.cls.netchan.outgoing_sequence;
|
||||
|
||||
// if we are too far out of date, just freeze
|
||||
if (current - ack >= Defines.CMD_BACKUP) {
|
||||
if (Globals.cl_showmiss.value != 0.0f)
|
||||
Com.Printf("exceeded CMD_BACKUP\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// copy current state to pmove
|
||||
//memset (pm, 0, sizeof(pm));
|
||||
pmove_t pm = new pmove_t();
|
||||
|
||||
pm.trace = new pmove_t.TraceAdapter() {
|
||||
public trace_t trace(float[] start, float[] mins, float[] maxs,
|
||||
float[] end) {
|
||||
return PMTrace(start, mins, maxs, end);
|
||||
}
|
||||
};
|
||||
pm.pointcontents = new pmove_t.PointContentsAdapter() {
|
||||
public int pointcontents(float[] point) {
|
||||
return PMpointcontents(point);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
PMove.pm_airaccelerate = Float
|
||||
.parseFloat(Globals.cl.configstrings[Defines.CS_AIRACCEL]);
|
||||
} catch (Exception e) {
|
||||
PMove.pm_airaccelerate = 0;
|
||||
}
|
||||
|
||||
// bugfix (rst) yeah !!!!!!!! found the solution to the B E W E G U N G
|
||||
// S P R O B L E M.
|
||||
pm.s.set(Globals.cl.frame.playerstate.pmove);
|
||||
|
||||
// SCR_DebugGraph (current - ack - 1, 0);
|
||||
int frame = 0;
|
||||
|
||||
// run frames
|
||||
usercmd_t cmd;
|
||||
while (++ack < current) {
|
||||
frame = ack & (Defines.CMD_BACKUP - 1);
|
||||
cmd = Globals.cl.cmds[frame];
|
||||
|
||||
pm.cmd.set(cmd);
|
||||
|
||||
PMove.Pmove(pm);
|
||||
|
||||
// save for debug checking
|
||||
Math3D.VectorCopy(pm.s.origin, Globals.cl.predicted_origins[frame]);
|
||||
}
|
||||
|
||||
int oldframe = (ack - 2) & (Defines.CMD_BACKUP - 1);
|
||||
int oldz = Globals.cl.predicted_origins[oldframe][2];
|
||||
int step = pm.s.origin[2] - oldz;
|
||||
if (step > 63 && step < 160
|
||||
&& (pm.s.pm_flags & pmove_t.PMF_ON_GROUND) != 0) {
|
||||
Globals.cl.predicted_step = step * 0.125f;
|
||||
Globals.cl.predicted_step_time = (int) (Globals.cls.realtime - Globals.cls.frametime * 500);
|
||||
}
|
||||
|
||||
// copy results out for rendering
|
||||
Globals.cl.predicted_origin[0] = pm.s.origin[0] * 0.125f;
|
||||
Globals.cl.predicted_origin[1] = pm.s.origin[1] * 0.125f;
|
||||
Globals.cl.predicted_origin[2] = pm.s.origin[2] * 0.125f;
|
||||
|
||||
Math3D.VectorCopy(pm.viewangles, Globals.cl.predicted_angles);
|
||||
}
|
||||
}
|
||||
1784
src/main/java/lwjake2/client/CL_tent.java
Normal file
1784
src/main/java/lwjake2/client/CL_tent.java
Normal file
File diff suppressed because it is too large
Load Diff
184
src/main/java/lwjake2/client/CL_view.java
Normal file
184
src/main/java/lwjake2/client/CL_view.java
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.qcommon.CM;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.sys.Sys;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class CL_view {
|
||||
|
||||
static int num_cl_weaponmodels;
|
||||
|
||||
static String[] cl_weaponmodels = new String[Defines.MAX_CLIENTWEAPONMODELS];
|
||||
|
||||
/*
|
||||
* =================
|
||||
*
|
||||
* CL_PrepRefresh
|
||||
*
|
||||
* Call before entering a new level, or after changing dlls
|
||||
* =================
|
||||
*/
|
||||
static void PrepRefresh() {
|
||||
String mapname;
|
||||
int i;
|
||||
String name;
|
||||
float rotate;
|
||||
float[] axis = new float[3];
|
||||
|
||||
if ((i = Globals.cl.configstrings[Defines.CS_MODELS + 1].length()) == 0)
|
||||
return; // no map loaded
|
||||
|
||||
SCR.AddDirtyPoint(0, 0);
|
||||
SCR.AddDirtyPoint(Globals.viddef.width - 1, Globals.viddef.height - 1);
|
||||
|
||||
// let the render dll load the map
|
||||
mapname = Globals.cl.configstrings[Defines.CS_MODELS + 1].substring(5,
|
||||
i - 4); // skip "maps/"
|
||||
// cut off ".bsp"
|
||||
|
||||
// register models, pics, and skins
|
||||
Com.Printf("Map: " + mapname + "\r");
|
||||
SCR.UpdateScreen();
|
||||
Globals.re.BeginRegistration(mapname);
|
||||
Com.Printf(" \r");
|
||||
|
||||
// precache status bar pics
|
||||
Com.Printf("pics\r");
|
||||
SCR.UpdateScreen();
|
||||
SCR.TouchPics();
|
||||
Com.Printf(" \r");
|
||||
|
||||
CL_tent.RegisterTEntModels();
|
||||
|
||||
num_cl_weaponmodels = 1;
|
||||
cl_weaponmodels[0] = "weapon.md2";
|
||||
|
||||
for (i = 1; i < Defines.MAX_MODELS
|
||||
&& Globals.cl.configstrings[Defines.CS_MODELS + i].length() != 0; i++) {
|
||||
name = new String(Globals.cl.configstrings[Defines.CS_MODELS + i]);
|
||||
if (name.length() > 37)
|
||||
name = name.substring(0, 36);
|
||||
|
||||
if (name.charAt(0) != '*')
|
||||
Com.Printf(name + "\r");
|
||||
|
||||
SCR.UpdateScreen();
|
||||
Sys.SendKeyEvents(); // pump message loop
|
||||
if (name.charAt(0) == '#') {
|
||||
// special player weapon model
|
||||
if (num_cl_weaponmodels < Defines.MAX_CLIENTWEAPONMODELS) {
|
||||
cl_weaponmodels[num_cl_weaponmodels] = Globals.cl.configstrings[Defines.CS_MODELS
|
||||
+ i].substring(1);
|
||||
num_cl_weaponmodels++;
|
||||
}
|
||||
} else {
|
||||
Globals.cl.model_draw[i] = Globals.re
|
||||
.RegisterModel(Globals.cl.configstrings[Defines.CS_MODELS
|
||||
+ i]);
|
||||
if (name.charAt(0) == '*')
|
||||
Globals.cl.model_clip[i] = CM
|
||||
.InlineModel(Globals.cl.configstrings[Defines.CS_MODELS
|
||||
+ i]);
|
||||
else
|
||||
Globals.cl.model_clip[i] = null;
|
||||
}
|
||||
if (name.charAt(0) != '*')
|
||||
Com.Printf(" \r");
|
||||
}
|
||||
|
||||
Com.Printf("images\r");
|
||||
SCR.UpdateScreen();
|
||||
for (i = 1; i < Defines.MAX_IMAGES
|
||||
&& Globals.cl.configstrings[Defines.CS_IMAGES + i].length() > 0; i++) {
|
||||
Globals.cl.image_precache[i] = Globals.re
|
||||
.RegisterPic(Globals.cl.configstrings[Defines.CS_IMAGES + i]);
|
||||
Sys.SendKeyEvents(); // pump message loop
|
||||
}
|
||||
|
||||
Com.Printf(" \r");
|
||||
for (i = 0; i < Defines.MAX_CLIENTS; i++) {
|
||||
if (Globals.cl.configstrings[Defines.CS_PLAYERSKINS + i].length() == 0)
|
||||
continue;
|
||||
Com.Printf("client " + i + '\r');
|
||||
SCR.UpdateScreen();
|
||||
Sys.SendKeyEvents(); // pump message loop
|
||||
CL_parse.ParseClientinfo(i);
|
||||
Com.Printf(" \r");
|
||||
}
|
||||
|
||||
CL_parse.LoadClientinfo(Globals.cl.baseclientinfo,
|
||||
"unnamed\\male/grunt");
|
||||
|
||||
// set sky textures and speed
|
||||
Com.Printf("sky\r");
|
||||
SCR.UpdateScreen();
|
||||
rotate = Float
|
||||
.parseFloat(Globals.cl.configstrings[Defines.CS_SKYROTATE]);
|
||||
StringTokenizer st = new StringTokenizer(
|
||||
Globals.cl.configstrings[Defines.CS_SKYAXIS]);
|
||||
axis[0] = Float.parseFloat(st.nextToken());
|
||||
axis[1] = Float.parseFloat(st.nextToken());
|
||||
axis[2] = Float.parseFloat(st.nextToken());
|
||||
Globals.re.SetSky(Globals.cl.configstrings[Defines.CS_SKY], rotate,
|
||||
axis);
|
||||
Com.Printf(" \r");
|
||||
|
||||
// the renderer can now free unneeded stuff
|
||||
Globals.re.EndRegistration();
|
||||
|
||||
// clear any lines of console text
|
||||
Console.ClearNotify();
|
||||
|
||||
SCR.UpdateScreen();
|
||||
Globals.cl.refresh_prepped = true;
|
||||
Globals.cl.force_refdef = true; // make sure we have a valid refdef
|
||||
}
|
||||
|
||||
public static void AddNetgraph() {
|
||||
int i;
|
||||
int in;
|
||||
int ping;
|
||||
|
||||
// if using the debuggraph for something else, don't
|
||||
// add the net lines
|
||||
if (SCR.scr_debuggraph.value == 0.0f || SCR.scr_timegraph.value == 0.0f)
|
||||
return;
|
||||
|
||||
for (i = 0; i < Globals.cls.netchan.dropped; i++)
|
||||
SCR.DebugGraph(30, 0x40);
|
||||
|
||||
for (i = 0; i < Globals.cl.surpressCount; i++)
|
||||
SCR.DebugGraph(30, 0xdf);
|
||||
|
||||
// see what the latency was on this packet
|
||||
in = Globals.cls.netchan.incoming_acknowledged
|
||||
& (Defines.CMD_BACKUP - 1);
|
||||
ping = (int) (Globals.cls.realtime - Globals.cl.cmd_time[in]);
|
||||
ping /= 30;
|
||||
if (ping > 30)
|
||||
ping = 30;
|
||||
SCR.DebugGraph(ping, 0xd0);
|
||||
}
|
||||
}
|
||||
595
src/main/java/lwjake2/client/Console.java
Normal file
595
src/main/java/lwjake2/client/Console.java
Normal file
@@ -0,0 +1,595 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.game.Cmd;
|
||||
import lwjake2.qcommon.Cbuf;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.qcommon.Cvar;
|
||||
import lwjake2.qcommon.FileSystem;
|
||||
import lwjake2.qcommon.BaseQ2FileSystem;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Vargs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Console
|
||||
*/
|
||||
@Slf4j
|
||||
public final class Console extends Globals {
|
||||
private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance();
|
||||
public static Runnable ToggleConsole_f = () -> {
|
||||
SCR.EndLoadingPlaque(); // get rid of loading plaque
|
||||
|
||||
if (Globals.cl.attractloop) {
|
||||
Cbuf.AddText("killserver\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Globals.cls.state == Defines.ca_disconnected) {
|
||||
// start the demo loop again
|
||||
Cbuf.AddText("d1\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Key.ClearTyping();
|
||||
Console.ClearNotify();
|
||||
|
||||
if (Globals.cls.key_dest == Defines.key_console) {
|
||||
Menu.ForceMenuOff();
|
||||
Cvar.Set("paused", "0");
|
||||
} else {
|
||||
Menu.ForceMenuOff();
|
||||
Globals.cls.key_dest = Defines.key_console;
|
||||
|
||||
if (Cvar.VariableValue("maxclients") == 1
|
||||
&& Globals.server_state != 0)
|
||||
Cvar.Set("paused", "1");
|
||||
}
|
||||
};
|
||||
|
||||
public static Runnable Clear_f = () -> Arrays.fill(Globals.con.text, (byte) ' ');
|
||||
|
||||
public static Runnable Dump_f = () -> {
|
||||
|
||||
int l, x;
|
||||
int line;
|
||||
RandomAccessFile f;
|
||||
byte[] buffer = new byte[1024];
|
||||
String name;
|
||||
|
||||
if (Cmd.Argc() != 2) {
|
||||
log.info("usage: condump <filename>");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(),
|
||||
// Cmd_Argv(1));
|
||||
name = fileSystem.getGamedir() + "/" + Cmd.Argv(1) + ".txt";
|
||||
|
||||
log.info("Dumped console text to {}", name);
|
||||
fileSystem.createPath(name);
|
||||
f = Lib.fopen(name, "rw");
|
||||
if (f == null) {
|
||||
log.error("ERROR: couldn't open.");
|
||||
return;
|
||||
}
|
||||
|
||||
// skip empty lines
|
||||
for (l = con.current - con.totallines + 1; l <= con.current; l++) {
|
||||
line = (l % con.totallines) * con.linewidth;
|
||||
for (x = 0; x < con.linewidth; x++)
|
||||
if (con.text[line + x] != ' ')
|
||||
break;
|
||||
if (x != con.linewidth)
|
||||
break;
|
||||
}
|
||||
|
||||
// write the remaining lines
|
||||
buffer[con.linewidth] = 0;
|
||||
for (; l <= con.current; l++) {
|
||||
line = (l % con.totallines) * con.linewidth;
|
||||
//strncpy (buffer, line, con.linewidth);
|
||||
System.arraycopy(con.text, line, buffer, 0, con.linewidth);
|
||||
for (x = con.linewidth - 1; x >= 0; x--) {
|
||||
if (buffer[x] == ' ')
|
||||
buffer[x] = 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
for (x = 0; buffer[x] != 0; x++)
|
||||
buffer[x] &= 0x7f;
|
||||
|
||||
buffer[x] = '\n';
|
||||
// fprintf (f, "%s\n", buffer);
|
||||
try {
|
||||
f.write(buffer, 0, x + 1);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
Lib.fclose(f);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static void Init() {
|
||||
Globals.con.linewidth = -1;
|
||||
|
||||
CheckResize();
|
||||
|
||||
log.info("Console initialized.");
|
||||
|
||||
//
|
||||
// register our commands
|
||||
//
|
||||
Globals.con_notifytime = Cvar.Get("con_notifytime", "3", 0);
|
||||
|
||||
Cmd.AddCommand("toggleconsole", ToggleConsole_f);
|
||||
Cmd.AddCommand("togglechat", ToggleChat_f);
|
||||
Cmd.AddCommand("messagemode", MessageMode_f);
|
||||
Cmd.AddCommand("messagemode2", MessageMode2_f);
|
||||
Cmd.AddCommand("clear", Clear_f);
|
||||
Cmd.AddCommand("condump", Dump_f);
|
||||
Globals.con.initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the line width has changed, reformat the buffer.
|
||||
*/
|
||||
public static void CheckResize() {
|
||||
|
||||
int width = (Globals.viddef.width >> 3) - 2;
|
||||
if (width > Defines.MAXCMDLINE) width = Defines.MAXCMDLINE;
|
||||
|
||||
if (width == Globals.con.linewidth)
|
||||
return;
|
||||
|
||||
if (width < 1) { // video hasn't been initialized yet
|
||||
width = 38;
|
||||
Globals.con.linewidth = width;
|
||||
Globals.con.totallines = Defines.CON_TEXTSIZE
|
||||
/ Globals.con.linewidth;
|
||||
Arrays.fill(Globals.con.text, (byte) ' ');
|
||||
} else {
|
||||
int oldwidth = Globals.con.linewidth;
|
||||
Globals.con.linewidth = width;
|
||||
int oldtotallines = Globals.con.totallines;
|
||||
Globals.con.totallines = Defines.CON_TEXTSIZE
|
||||
/ Globals.con.linewidth;
|
||||
int numlines = oldtotallines;
|
||||
|
||||
if (Globals.con.totallines < numlines)
|
||||
numlines = Globals.con.totallines;
|
||||
|
||||
int numchars = oldwidth;
|
||||
|
||||
if (Globals.con.linewidth < numchars)
|
||||
numchars = Globals.con.linewidth;
|
||||
|
||||
byte[] tbuf = new byte[Defines.CON_TEXTSIZE];
|
||||
System
|
||||
.arraycopy(Globals.con.text, 0, tbuf, 0,
|
||||
Defines.CON_TEXTSIZE);
|
||||
Arrays.fill(Globals.con.text, (byte) ' ');
|
||||
|
||||
for (int i = 0; i < numlines; i++) {
|
||||
for (int j = 0; j < numchars; j++) {
|
||||
Globals.con.text[(Globals.con.totallines - 1 - i)
|
||||
* Globals.con.linewidth + j] = tbuf[((Globals.con.current
|
||||
- i + oldtotallines) % oldtotallines)
|
||||
* oldwidth + j];
|
||||
}
|
||||
}
|
||||
|
||||
Console.ClearNotify();
|
||||
}
|
||||
|
||||
Globals.con.current = Globals.con.totallines - 1;
|
||||
Globals.con.display = Globals.con.current;
|
||||
}
|
||||
|
||||
public static void ClearNotify() {
|
||||
int i;
|
||||
for (i = 0; i < Defines.NUM_CON_TIMES; i++)
|
||||
Globals.con.times[i] = 0;
|
||||
}
|
||||
|
||||
static void DrawString(int x, int y, String s) {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
Globals.re.DrawChar(x, y, s.charAt(i));
|
||||
x += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawAltString(int x, int y, String s) {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
Globals.re.DrawChar(x, y, s.charAt(i) ^ 0x80);
|
||||
x += 8;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ Con_ToggleChat_f ================
|
||||
*/
|
||||
static Runnable ToggleChat_f = () -> {
|
||||
Key.ClearTyping();
|
||||
|
||||
if (cls.key_dest == key_console) {
|
||||
if (cls.state == ca_active) {
|
||||
Menu.ForceMenuOff();
|
||||
cls.key_dest = key_game;
|
||||
}
|
||||
} else
|
||||
cls.key_dest = key_console;
|
||||
|
||||
ClearNotify();
|
||||
};
|
||||
|
||||
/*
|
||||
* ================ Con_MessageMode_f ================
|
||||
*/
|
||||
static Runnable MessageMode_f = () -> {
|
||||
chat_team = false;
|
||||
cls.key_dest = key_message;
|
||||
};
|
||||
|
||||
/*
|
||||
* ================ Con_MessageMode2_f ================
|
||||
*/
|
||||
static Runnable MessageMode2_f = () -> {
|
||||
chat_team = true;
|
||||
cls.key_dest = key_message;
|
||||
};
|
||||
|
||||
/*
|
||||
* =============== Con_Linefeed ===============
|
||||
*/
|
||||
static void Linefeed() {
|
||||
Globals.con.x = 0;
|
||||
if (Globals.con.display == Globals.con.current)
|
||||
Globals.con.display++;
|
||||
Globals.con.current++;
|
||||
int i = (Globals.con.current % Globals.con.totallines)
|
||||
* Globals.con.linewidth;
|
||||
int e = i + Globals.con.linewidth;
|
||||
while (i++ < e)
|
||||
Globals.con.text[i] = ' ';
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ Con_Print
|
||||
*
|
||||
* Handles cursor positioning, line wrapping, etc All console printing must
|
||||
* go through this in order to be logged to disk If no console is visible,
|
||||
* the text will appear at the top of the game window ================
|
||||
*/
|
||||
private static int cr;
|
||||
|
||||
public static void Print(String txt) {
|
||||
int y;
|
||||
int c, l;
|
||||
int mask;
|
||||
int txtpos = 0;
|
||||
|
||||
if (!con.initialized)
|
||||
return;
|
||||
|
||||
if (txt.charAt(0) == 1 || txt.charAt(0) == 2) {
|
||||
mask = 128; // go to colored text
|
||||
txtpos++;
|
||||
} else
|
||||
mask = 0;
|
||||
|
||||
while (txtpos < txt.length()) {
|
||||
c = txt.charAt(txtpos);
|
||||
// count word length
|
||||
for (l = 0; l < con.linewidth && l < (txt.length() - txtpos); l++)
|
||||
if (txt.charAt(l + txtpos) <= ' ')
|
||||
break;
|
||||
|
||||
// word wrap
|
||||
if (l != con.linewidth && (con.x + l > con.linewidth))
|
||||
con.x = 0;
|
||||
|
||||
txtpos++;
|
||||
|
||||
if (cr != 0) {
|
||||
con.current--;
|
||||
cr = 0;
|
||||
}
|
||||
|
||||
if (con.x == 0) {
|
||||
Console.Linefeed();
|
||||
// mark time for transparent overlay
|
||||
if (con.current >= 0)
|
||||
con.times[con.current % NUM_CON_TIMES] = cls.realtime;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case '\n':
|
||||
con.x = 0;
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
con.x = 0;
|
||||
cr = 1;
|
||||
break;
|
||||
|
||||
default: // display character and advance
|
||||
y = con.current % con.totallines;
|
||||
con.text[y * con.linewidth + con.x] = (byte) (c | mask | con.ormask);
|
||||
con.x++;
|
||||
if (con.x >= con.linewidth)
|
||||
con.x = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ============== Con_CenteredPrint ==============
|
||||
*/
|
||||
static void CenteredPrint(String text) {
|
||||
int l = text.length();
|
||||
l = (con.linewidth - l) / 2;
|
||||
if (l < 0)
|
||||
l = 0;
|
||||
|
||||
StringBuffer sb = new StringBuffer(1024);
|
||||
for (int i = 0; i < l; i++)
|
||||
sb.append(' ');
|
||||
sb.append(text);
|
||||
sb.append('\n');
|
||||
|
||||
sb.setLength(1024);
|
||||
|
||||
Console.Print(sb.toString());
|
||||
}
|
||||
|
||||
/*
|
||||
* ==============================================================================
|
||||
*
|
||||
* DRAWING
|
||||
*
|
||||
* ==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================ Con_DrawInput
|
||||
*
|
||||
* The input line scrolls horizontally if typing goes beyond the right edge
|
||||
* ================
|
||||
*/
|
||||
static void DrawInput() {
|
||||
int i;
|
||||
byte[] text;
|
||||
|
||||
if (cls.key_dest == key_menu)
|
||||
return;
|
||||
if (cls.key_dest != key_console && cls.state == ca_active)
|
||||
return; // don't draw anything (always draw if not active)
|
||||
|
||||
text = key_lines[edit_line];
|
||||
|
||||
// add the cursor frame
|
||||
text[key_linepos] = (byte) (10 + ((int) (cls.realtime >> 8) & 1));
|
||||
|
||||
// fill out remainder with spaces
|
||||
for (i = key_linepos + 1; i < con.linewidth; i++)
|
||||
text[i] = ' ';
|
||||
|
||||
// prestep if horizontally scrolling
|
||||
//if (key_linepos >= con.linewidth)
|
||||
// start += 1 + key_linepos - con.linewidth;
|
||||
|
||||
// draw it
|
||||
// y = con.vislines-16;
|
||||
|
||||
for (i = 0; i < con.linewidth; i++)
|
||||
re.DrawChar((i + 1) << 3, con.vislines - 22, text[i]);
|
||||
|
||||
// remove cursor
|
||||
key_lines[edit_line][key_linepos] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ Con_DrawNotify
|
||||
*
|
||||
* Draws the last few lines of output transparently over the game top
|
||||
* ================
|
||||
*/
|
||||
static void DrawNotify() {
|
||||
int x, v;
|
||||
int text;
|
||||
int i;
|
||||
int time;
|
||||
String s;
|
||||
int skip;
|
||||
|
||||
v = 0;
|
||||
for (i = con.current - NUM_CON_TIMES + 1; i <= con.current; i++) {
|
||||
if (i < 0)
|
||||
continue;
|
||||
|
||||
time = (int) con.times[i % NUM_CON_TIMES];
|
||||
if (time == 0)
|
||||
continue;
|
||||
|
||||
time = (int) (cls.realtime - time);
|
||||
if (time > con_notifytime.value * 1000)
|
||||
continue;
|
||||
|
||||
text = (i % con.totallines) * con.linewidth;
|
||||
|
||||
for (x = 0; x < con.linewidth; x++)
|
||||
re.DrawChar((x + 1) << 3, v, con.text[text + x]);
|
||||
|
||||
v += 8;
|
||||
}
|
||||
|
||||
if (cls.key_dest == key_message) {
|
||||
if (chat_team) {
|
||||
DrawString(8, v, "say_team:");
|
||||
skip = 11;
|
||||
} else {
|
||||
DrawString(8, v, "say:");
|
||||
skip = 5;
|
||||
}
|
||||
|
||||
s = chat_buffer;
|
||||
if (chat_bufferlen > (viddef.width >> 3) - (skip + 1))
|
||||
s = s.substring(chat_bufferlen
|
||||
- ((viddef.width >> 3) - (skip + 1)));
|
||||
|
||||
for (x = 0; x < s.length(); x++) {
|
||||
re.DrawChar((x + skip) << 3, v, s.charAt(x));
|
||||
}
|
||||
re.DrawChar((x + skip) << 3, v,
|
||||
(int) (10 + ((cls.realtime >> 8) & 1)));
|
||||
v += 8;
|
||||
}
|
||||
|
||||
if (v != 0) {
|
||||
SCR.AddDirtyPoint(0, 0);
|
||||
SCR.AddDirtyPoint(viddef.width - 1, v);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ Con_DrawConsole
|
||||
*
|
||||
* Draws the console with the solid background ================
|
||||
*/
|
||||
static void DrawConsole(float frac) {
|
||||
int i, j, x, y, n;
|
||||
int rows;
|
||||
int text;
|
||||
int row;
|
||||
int lines;
|
||||
String version;
|
||||
|
||||
lines = (int) (viddef.height * frac);
|
||||
if (lines <= 0)
|
||||
return;
|
||||
|
||||
if (lines > viddef.height)
|
||||
lines = viddef.height;
|
||||
|
||||
// draw the background
|
||||
re.DrawStretchPic(0, -viddef.height + lines, viddef.width,
|
||||
viddef.height, "conback");
|
||||
SCR.AddDirtyPoint(0, 0);
|
||||
SCR.AddDirtyPoint(viddef.width - 1, lines - 1);
|
||||
|
||||
version = Com.sprintf("v%4.2f", new Vargs(1).add(VERSION));
|
||||
for (x = 0; x < 5; x++)
|
||||
re.DrawChar(viddef.width - 44 + x * 8, lines - 12, 128 + version
|
||||
.charAt(x));
|
||||
|
||||
// draw the text
|
||||
con.vislines = lines;
|
||||
|
||||
rows = (lines - 22) >> 3; // rows of text to draw
|
||||
|
||||
y = lines - 30;
|
||||
|
||||
// draw from the bottom up
|
||||
if (con.display != con.current) {
|
||||
// draw arrows to show the buffer is backscrolled
|
||||
for (x = 0; x < con.linewidth; x += 4)
|
||||
re.DrawChar((x + 1) << 3, y, '^');
|
||||
|
||||
y -= 8;
|
||||
rows--;
|
||||
}
|
||||
|
||||
row = con.display;
|
||||
for (i = 0; i < rows; i++, y -= 8, row--) {
|
||||
if (row < 0)
|
||||
break;
|
||||
if (con.current - row >= con.totallines)
|
||||
break; // past scrollback wrap point
|
||||
|
||||
int first = (row % con.totallines) * con.linewidth;
|
||||
|
||||
for (x = 0; x < con.linewidth; x++)
|
||||
re.DrawChar((x + 1) << 3, y, con.text[x + first]);
|
||||
}
|
||||
|
||||
//ZOID
|
||||
// draw the download bar
|
||||
// figure out width
|
||||
if (cls.download != null) {
|
||||
if ((text = cls.downloadname.lastIndexOf('/')) != 0)
|
||||
text++;
|
||||
else
|
||||
text = 0;
|
||||
|
||||
x = con.linewidth - ((con.linewidth * 7) / 40);
|
||||
y = x - (cls.downloadname.length() - text) - 8;
|
||||
i = con.linewidth / 3;
|
||||
StringBuffer dlbar = new StringBuffer(512);
|
||||
if (cls.downloadname.length() - text > i) {
|
||||
y = x - i - 11;
|
||||
int end = text + i - 1;
|
||||
;
|
||||
dlbar.append(cls.downloadname.substring(text, end));
|
||||
dlbar.append("...");
|
||||
} else {
|
||||
dlbar.append(cls.downloadname.substring(text));
|
||||
}
|
||||
dlbar.append(": ");
|
||||
dlbar.append((char) 0x80);
|
||||
|
||||
// where's the dot go?
|
||||
if (cls.downloadpercent == 0)
|
||||
n = 0;
|
||||
else
|
||||
n = y * cls.downloadpercent / 100;
|
||||
|
||||
for (j = 0; j < y; j++) {
|
||||
if (j == n)
|
||||
dlbar.append((char) 0x83);
|
||||
else
|
||||
dlbar.append((char) 0x81);
|
||||
}
|
||||
dlbar.append((char) 0x82);
|
||||
dlbar.append((cls.downloadpercent < 10) ? " 0" : " ");
|
||||
dlbar.append(cls.downloadpercent).append('%');
|
||||
// draw it
|
||||
y = con.vislines - 12;
|
||||
for (i = 0; i < dlbar.length(); i++)
|
||||
re.DrawChar((i + 1) << 3, y, dlbar.charAt(i));
|
||||
}
|
||||
//ZOID
|
||||
|
||||
// draw the input prompt, user text, and cursor if desired
|
||||
DrawInput();
|
||||
}
|
||||
}
|
||||
813
src/main/java/lwjake2/client/Key.java
Normal file
813
src/main/java/lwjake2/client/Key.java
Normal file
@@ -0,0 +1,813 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.game.Cmd;
|
||||
import lwjake2.qcommon.Cbuf;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.qcommon.Cvar;
|
||||
import lwjake2.util.Lib;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Key
|
||||
*/
|
||||
@Slf4j
|
||||
public class Key extends Globals {
|
||||
//
|
||||
// these are the key numbers that should be passed to Key_Event
|
||||
//
|
||||
public static final int K_TAB = 9;
|
||||
public static final int K_ENTER = 13;
|
||||
public static final int K_ESCAPE = 27;
|
||||
public static final int K_SPACE = 32;
|
||||
|
||||
// normal keys should be passed as lowercased ascii
|
||||
|
||||
public static final int K_BACKSPACE = 127;
|
||||
public static final int K_UPARROW = 128;
|
||||
public static final int K_DOWNARROW = 129;
|
||||
public static final int K_LEFTARROW = 130;
|
||||
public static final int K_RIGHTARROW = 131;
|
||||
|
||||
public static final int K_ALT = 132;
|
||||
public static final int K_CTRL = 133;
|
||||
public static final int K_SHIFT = 134;
|
||||
public static final int K_F1 = 135;
|
||||
public static final int K_F2 = 136;
|
||||
public static final int K_F3 = 137;
|
||||
public static final int K_F4 = 138;
|
||||
public static final int K_F5 = 139;
|
||||
public static final int K_F6 = 140;
|
||||
public static final int K_F7 = 141;
|
||||
public static final int K_F8 = 142;
|
||||
public static final int K_F9 = 143;
|
||||
public static final int K_F10 = 144;
|
||||
public static final int K_F11 = 145;
|
||||
public static final int K_F12 = 146;
|
||||
public static final int K_INS = 147;
|
||||
public static final int K_DEL = 148;
|
||||
public static final int K_PGDN = 149;
|
||||
public static final int K_PGUP = 150;
|
||||
public static final int K_HOME = 151;
|
||||
public static final int K_END = 152;
|
||||
|
||||
public static final int K_KP_HOME = 160;
|
||||
public static final int K_KP_UPARROW = 161;
|
||||
public static final int K_KP_PGUP = 162;
|
||||
public static final int K_KP_LEFTARROW = 163;
|
||||
public static final int K_KP_5 = 164;
|
||||
public static final int K_KP_RIGHTARROW = 165;
|
||||
public static final int K_KP_END = 166;
|
||||
public static final int K_KP_DOWNARROW = 167;
|
||||
public static final int K_KP_PGDN = 168;
|
||||
public static final int K_KP_ENTER = 169;
|
||||
public static final int K_KP_INS = 170;
|
||||
public static final int K_KP_DEL = 171;
|
||||
public static final int K_KP_SLASH = 172;
|
||||
public static final int K_KP_MINUS = 173;
|
||||
public static final int K_KP_PLUS = 174;
|
||||
|
||||
public static final int K_PAUSE = 255;
|
||||
|
||||
//
|
||||
// mouse buttons generate virtual keys
|
||||
//
|
||||
public static final int K_MOUSE1 = 200;
|
||||
public static final int K_MOUSE2 = 201;
|
||||
public static final int K_MOUSE3 = 202;
|
||||
|
||||
//
|
||||
// joystick buttons
|
||||
//
|
||||
public static final int K_JOY1 = 203;
|
||||
public static final int K_JOY2 = 204;
|
||||
public static final int K_JOY3 = 205;
|
||||
public static final int K_JOY4 = 206;
|
||||
|
||||
public static final int K_MWHEELDOWN = 239;
|
||||
public static final int K_MWHEELUP = 240;
|
||||
|
||||
static int anykeydown = 0;
|
||||
static int key_waiting;
|
||||
static int history_line = 0;
|
||||
static boolean shift_down = false;
|
||||
static int[] key_repeats = new int[256];
|
||||
//static int[] keyshift = new int[256];
|
||||
static boolean[] menubound = new boolean[256];
|
||||
static boolean[] consolekeys = new boolean[256];
|
||||
|
||||
static String[] keynames = new String[256];
|
||||
|
||||
static {
|
||||
keynames[K_TAB] = "TAB";
|
||||
keynames[K_ENTER] = "ENTER";
|
||||
keynames[K_ESCAPE] = "ESCAPE";
|
||||
keynames[K_SPACE] = "SPACE";
|
||||
keynames[K_BACKSPACE] = "BACKSPACE";
|
||||
keynames[K_UPARROW] = "UPARROW";
|
||||
keynames[K_DOWNARROW] = "DOWNARROW";
|
||||
keynames[K_LEFTARROW] = "LEFTARROW";
|
||||
keynames[K_RIGHTARROW] = "RIGHTARROW";
|
||||
keynames[K_ALT] = "ALT";
|
||||
keynames[K_CTRL] = "CTRL";
|
||||
keynames[K_SHIFT] = "SHIFT";
|
||||
|
||||
keynames[K_F1] = "F1";
|
||||
keynames[K_F2] = "F2";
|
||||
keynames[K_F3] = "F3";
|
||||
keynames[K_F4] = "F4";
|
||||
keynames[K_F5] = "F5";
|
||||
keynames[K_F6] = "F6";
|
||||
keynames[K_F7] = "F7";
|
||||
keynames[K_F8] = "F8";
|
||||
keynames[K_F9] = "F9";
|
||||
keynames[K_F10] = "F10";
|
||||
keynames[K_F11] = "F11";
|
||||
keynames[K_F12] = "F12";
|
||||
|
||||
keynames[K_INS] = "INS";
|
||||
keynames[K_DEL] = "DEL";
|
||||
keynames[K_PGDN] = "PGDN";
|
||||
keynames[K_PGUP] = "PGUP";
|
||||
keynames[K_HOME] = "HOME";
|
||||
keynames[K_END] = "END";
|
||||
|
||||
keynames[K_MOUSE1] = "MOUSE1";
|
||||
keynames[K_MOUSE2] = "MOUSE2";
|
||||
keynames[K_MOUSE3] = "MOUSE3";
|
||||
|
||||
// 00092 {"JOY1", K_JOY1},
|
||||
// 00093 {"JOY2", K_JOY2},
|
||||
// 00094 {"JOY3", K_JOY3},
|
||||
// 00095 {"JOY4", K_JOY4},
|
||||
|
||||
keynames[K_KP_HOME] = "KP_HOME";
|
||||
keynames[K_KP_UPARROW] = "KP_UPARROW";
|
||||
keynames[K_KP_PGUP] = "KP_PGUP";
|
||||
keynames[K_KP_LEFTARROW] = "KP_LEFTARROW";
|
||||
keynames[K_KP_5] = "KP_5";
|
||||
keynames[K_KP_RIGHTARROW] = "KP_RIGHTARROW";
|
||||
keynames[K_KP_END] = "KP_END";
|
||||
keynames[K_KP_DOWNARROW] = "KP_DOWNARROW";
|
||||
keynames[K_KP_PGDN] = "KP_PGDN";
|
||||
keynames[K_KP_ENTER] = "KP_ENTER";
|
||||
keynames[K_KP_INS] = "KP_INS";
|
||||
keynames[K_KP_DEL] = "KP_DEL";
|
||||
keynames[K_KP_SLASH] = "KP_SLASH";
|
||||
|
||||
keynames[K_KP_PLUS] = "KP_PLUS";
|
||||
keynames[K_KP_MINUS] = "KP_MINUS";
|
||||
|
||||
keynames[K_MWHEELUP] = "MWHEELUP";
|
||||
keynames[K_MWHEELDOWN] = "MWHEELDOWN";
|
||||
|
||||
keynames[K_PAUSE] = "PAUSE";
|
||||
keynames[';'] = "SEMICOLON"; // because a raw semicolon seperates commands
|
||||
|
||||
keynames[0] = "NULL";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static void Init() {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
Globals.key_lines[i][0] = ']';
|
||||
Globals.key_lines[i][1] = 0;
|
||||
}
|
||||
Globals.key_linepos = 1;
|
||||
|
||||
//
|
||||
// init ascii characters in console mode
|
||||
//
|
||||
for (int i = 32; i < 128; i++)
|
||||
consolekeys[i] = true;
|
||||
consolekeys[K_ENTER] = true;
|
||||
consolekeys[K_KP_ENTER] = true;
|
||||
consolekeys[K_TAB] = true;
|
||||
consolekeys[K_LEFTARROW] = true;
|
||||
consolekeys[K_KP_LEFTARROW] = true;
|
||||
consolekeys[K_RIGHTARROW] = true;
|
||||
consolekeys[K_KP_RIGHTARROW] = true;
|
||||
consolekeys[K_UPARROW] = true;
|
||||
consolekeys[K_KP_UPARROW] = true;
|
||||
consolekeys[K_DOWNARROW] = true;
|
||||
consolekeys[K_KP_DOWNARROW] = true;
|
||||
consolekeys[K_BACKSPACE] = true;
|
||||
consolekeys[K_HOME] = true;
|
||||
consolekeys[K_KP_HOME] = true;
|
||||
consolekeys[K_END] = true;
|
||||
consolekeys[K_KP_END] = true;
|
||||
consolekeys[K_PGUP] = true;
|
||||
consolekeys[K_KP_PGUP] = true;
|
||||
consolekeys[K_PGDN] = true;
|
||||
consolekeys[K_KP_PGDN] = true;
|
||||
consolekeys[K_SHIFT] = true;
|
||||
consolekeys[K_INS] = true;
|
||||
consolekeys[K_KP_INS] = true;
|
||||
consolekeys[K_KP_DEL] = true;
|
||||
consolekeys[K_KP_SLASH] = true;
|
||||
consolekeys[K_KP_PLUS] = true;
|
||||
consolekeys[K_KP_MINUS] = true;
|
||||
consolekeys[K_KP_5] = true;
|
||||
|
||||
consolekeys['`'] = false;
|
||||
consolekeys['~'] = false;
|
||||
|
||||
// for (int i = 0; i < 256; i++)
|
||||
// keyshift[i] = i;
|
||||
// for (int i = 'a'; i <= 'z'; i++)
|
||||
// keyshift[i] = i - 'a' + 'A';
|
||||
// keyshift['1'] = '!';
|
||||
// keyshift['2'] = '@';
|
||||
// keyshift['3'] = '#';
|
||||
// keyshift['4'] = '$';
|
||||
// keyshift['5'] = '%';
|
||||
// keyshift['6'] = '^';
|
||||
// keyshift['7'] = '&';
|
||||
// keyshift['8'] = '*';
|
||||
// keyshift['9'] = '(';
|
||||
// keyshift['0'] = ')';
|
||||
// keyshift['-'] = '_';
|
||||
// keyshift['='] = '+';
|
||||
// keyshift[','] = '<';
|
||||
// keyshift['.'] = '>';
|
||||
// keyshift['/'] = '?';
|
||||
// keyshift[';'] = ':';
|
||||
// keyshift['\''] = '"';
|
||||
// keyshift['['] = '{';
|
||||
// keyshift[']'] = '}';
|
||||
// keyshift['`'] = '~';
|
||||
// keyshift['\\'] = '|';
|
||||
|
||||
menubound[K_ESCAPE] = true;
|
||||
for (int i = 0; i < 12; i++)
|
||||
menubound[K_F1 + i] = true;
|
||||
|
||||
//
|
||||
// register our functions
|
||||
//
|
||||
Cmd.AddCommand("bind", Key.Bind_f);
|
||||
Cmd.AddCommand("unbind", Key.Unbind_f);
|
||||
Cmd.AddCommand("unbindall", Key.Unbindall_f);
|
||||
Cmd.AddCommand("bindlist", Key.Bindlist_f);
|
||||
}
|
||||
|
||||
public static void ClearTyping() {
|
||||
Globals.key_lines[Globals.edit_line][1] = 0; // clear any typing
|
||||
Globals.key_linepos = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the system between frames for both key up and key down events.
|
||||
*/
|
||||
public static void Event(int key, boolean down, int time) {
|
||||
String kb;
|
||||
String cmd;
|
||||
|
||||
// hack for modal presses
|
||||
if (key_waiting == -1) {
|
||||
if (down)
|
||||
key_waiting = key;
|
||||
return;
|
||||
}
|
||||
|
||||
// update auto-repeat status
|
||||
if (down) {
|
||||
key_repeats[key]++;
|
||||
if (key_repeats[key] > 1
|
||||
&& Globals.cls.key_dest == Defines.key_game
|
||||
&& !(Globals.cls.state == Defines.ca_disconnected))
|
||||
return; // ignore most autorepeats
|
||||
|
||||
if (key >= 200 && Globals.keybindings[key] == null)
|
||||
Com.Printf(Key.KeynumToString(key) + " is unbound, hit F4 to set.\n");
|
||||
}
|
||||
else {
|
||||
key_repeats[key] = 0;
|
||||
}
|
||||
|
||||
if (key == K_SHIFT)
|
||||
shift_down = down;
|
||||
|
||||
// console key is hardcoded, so the user can never unbind it
|
||||
if (key == '`' || key == '~') {
|
||||
if (!down)
|
||||
return;
|
||||
|
||||
Console.ToggleConsole_f.run();
|
||||
return;
|
||||
}
|
||||
|
||||
// any key during the attract mode will bring up the menu
|
||||
if (Globals.cl.attractloop && Globals.cls.key_dest != Defines.key_menu && !(key >= K_F1 && key <= K_F12))
|
||||
key = K_ESCAPE;
|
||||
|
||||
// menu key is hardcoded, so the user can never unbind it
|
||||
if (key == K_ESCAPE) {
|
||||
if (!down)
|
||||
return;
|
||||
|
||||
if (Globals.cl.frame.playerstate.stats[Defines.STAT_LAYOUTS] != 0 && Globals.cls.key_dest == Defines.key_game) {
|
||||
// put away help computer / inventory
|
||||
Cbuf.AddText("cmd putaway\n");
|
||||
return;
|
||||
}
|
||||
switch (Globals.cls.key_dest) {
|
||||
case Defines.key_message :
|
||||
Key.Message(key);
|
||||
break;
|
||||
case Defines.key_menu :
|
||||
Menu.Keydown(key);
|
||||
break;
|
||||
case Defines.key_game :
|
||||
case Defines.key_console :
|
||||
Menu.Menu_Main_f();
|
||||
break;
|
||||
default :
|
||||
Com.Error(Defines.ERR_FATAL, "Bad cls.key_dest");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// track if any key is down for BUTTON_ANY
|
||||
Globals.keydown[key] = down;
|
||||
if (down) {
|
||||
if (key_repeats[key] == 1)
|
||||
Key.anykeydown++;
|
||||
}
|
||||
else {
|
||||
Key.anykeydown--;
|
||||
if (Key.anykeydown < 0)
|
||||
Key.anykeydown = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// key up events only generate commands if the game key binding is
|
||||
// a button command (leading + sign). These will occur even in console mode,
|
||||
// to keep the character from continuing an action started before a console
|
||||
// switch. Button commands include the kenum as a parameter, so multiple
|
||||
// downs can be matched with ups
|
||||
//
|
||||
if (!down) {
|
||||
kb = Globals.keybindings[key];
|
||||
if (kb != null && kb.length()>0 && kb.charAt(0) == '+') {
|
||||
cmd = "-" + kb.substring(1) + " " + key + " " + time + "\n";
|
||||
Cbuf.AddText(cmd);
|
||||
}
|
||||
// if (keyshift[key] != key) {
|
||||
// kb = Globals.keybindings[keyshift[key]];
|
||||
// if (kb != null && kb.length()>0 && kb.charAt(0) == '+') {
|
||||
// cmd = "-" + kb.substring(1) + " " + key + " " + time + "\n";
|
||||
// Cbuf.AddText(cmd);
|
||||
// }
|
||||
// }
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// if not a consolekey, send to the interpreter no matter what mode is
|
||||
//
|
||||
if ((Globals.cls.key_dest == Defines.key_menu && menubound[key])
|
||||
|| (Globals.cls.key_dest == Defines.key_console && !consolekeys[key])
|
||||
|| (Globals.cls.key_dest == Defines.key_game && (Globals.cls.state == Defines.ca_active || !consolekeys[key]))) {
|
||||
kb = Globals.keybindings[key];
|
||||
if (kb != null) {
|
||||
if (kb.length()>0 && kb.charAt(0) == '+') {
|
||||
// button commands add keynum and time as a parm
|
||||
cmd = kb + " " + key + " " + time + "\n";
|
||||
Cbuf.AddText(cmd);
|
||||
}
|
||||
else {
|
||||
Cbuf.AddText(kb + "\n");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if (shift_down)
|
||||
// key = keyshift[key];
|
||||
|
||||
switch (Globals.cls.key_dest) {
|
||||
case Defines.key_message :
|
||||
Key.Message(key);
|
||||
break;
|
||||
case Defines.key_menu :
|
||||
Menu.Keydown(key);
|
||||
break;
|
||||
|
||||
case Defines.key_game :
|
||||
case Defines.key_console :
|
||||
Key.Console(key);
|
||||
break;
|
||||
default :
|
||||
Com.Error(Defines.ERR_FATAL, "Bad cls.key_dest");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string (either a single ascii char, or a K_* name) for the
|
||||
* given keynum.
|
||||
*/
|
||||
public static String KeynumToString(int keynum) {
|
||||
if (keynum < 0 || keynum > 255)
|
||||
return "<KEY NOT FOUND>";
|
||||
if (keynum > 32 && keynum < 127)
|
||||
return Character.toString((char) keynum);
|
||||
|
||||
if (keynames[keynum] != null)
|
||||
return keynames[keynum];
|
||||
|
||||
return "<UNKNOWN KEYNUM>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a key number to be used to index keybindings[] by looking at
|
||||
* the given string. Single ascii characters return themselves, while
|
||||
* the K_* names are matched up.
|
||||
*/
|
||||
static int StringToKeynum(String str) {
|
||||
|
||||
if (str == null)
|
||||
return -1;
|
||||
|
||||
if (str.length() == 1)
|
||||
return str.charAt(0);
|
||||
|
||||
for (int i = 0; i < keynames.length; i++) {
|
||||
if (str.equalsIgnoreCase(keynames[i]))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void Message(int key) {
|
||||
|
||||
if (key == K_ENTER || key == K_KP_ENTER) {
|
||||
if (Globals.chat_team)
|
||||
Cbuf.AddText("say_team \"");
|
||||
else
|
||||
Cbuf.AddText("say \"");
|
||||
|
||||
Cbuf.AddText(Globals.chat_buffer);
|
||||
Cbuf.AddText("\"\n");
|
||||
|
||||
Globals.cls.key_dest = Defines.key_game;
|
||||
Globals.chat_buffer = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_ESCAPE) {
|
||||
Globals.cls.key_dest = Defines.key_game;
|
||||
Globals.chat_buffer = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (key < 32 || key > 127)
|
||||
return; // non printable
|
||||
|
||||
if (key == K_BACKSPACE) {
|
||||
if (Globals.chat_buffer.length() > 2) {
|
||||
Globals.chat_buffer = Globals.chat_buffer.substring(0, Globals.chat_buffer.length() - 2);
|
||||
}
|
||||
else
|
||||
Globals.chat_buffer = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (Globals.chat_buffer.length() > Defines.MAXCMDLINE)
|
||||
return; // all full
|
||||
|
||||
Globals.chat_buffer += (char) key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interactive line editing and console scrollback.
|
||||
*/
|
||||
public static void Console(int key) {
|
||||
|
||||
switch (key) {
|
||||
case K_KP_SLASH :
|
||||
key = '/';
|
||||
break;
|
||||
case K_KP_MINUS :
|
||||
key = '-';
|
||||
break;
|
||||
case K_KP_PLUS :
|
||||
key = '+';
|
||||
break;
|
||||
case K_KP_HOME :
|
||||
key = '7';
|
||||
break;
|
||||
case K_KP_UPARROW :
|
||||
key = '8';
|
||||
break;
|
||||
case K_KP_PGUP :
|
||||
key = '9';
|
||||
break;
|
||||
case K_KP_LEFTARROW :
|
||||
key = '4';
|
||||
break;
|
||||
case K_KP_5 :
|
||||
key = '5';
|
||||
break;
|
||||
case K_KP_RIGHTARROW :
|
||||
key = '6';
|
||||
break;
|
||||
case K_KP_END :
|
||||
key = '1';
|
||||
break;
|
||||
case K_KP_DOWNARROW :
|
||||
key = '2';
|
||||
break;
|
||||
case K_KP_PGDN :
|
||||
key = '3';
|
||||
break;
|
||||
case K_KP_INS :
|
||||
key = '0';
|
||||
break;
|
||||
case K_KP_DEL :
|
||||
key = '.';
|
||||
break;
|
||||
}
|
||||
|
||||
if (key == 'l') {
|
||||
if (Globals.keydown[K_CTRL]) {
|
||||
Cbuf.AddText("clear\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (key == K_ENTER || key == K_KP_ENTER) {
|
||||
// backslash text are commands, else chat
|
||||
if (Globals.key_lines[Globals.edit_line][1] == '\\' || Globals.key_lines[Globals.edit_line][1] == '/')
|
||||
Cbuf.AddText(
|
||||
new String(Globals.key_lines[Globals.edit_line], 2, Lib.strlen(Globals.key_lines[Globals.edit_line]) - 2));
|
||||
else
|
||||
Cbuf.AddText(
|
||||
new String(Globals.key_lines[Globals.edit_line], 1, Lib.strlen(Globals.key_lines[Globals.edit_line]) - 1));
|
||||
|
||||
|
||||
Cbuf.AddText("\n");
|
||||
|
||||
log.info(new String(Globals.key_lines[Globals.edit_line], 0, Lib.strlen(Globals.key_lines[Globals.edit_line])));
|
||||
Globals.edit_line = (Globals.edit_line + 1) & 31;
|
||||
history_line = Globals.edit_line;
|
||||
|
||||
Globals.key_lines[Globals.edit_line][0] = ']';
|
||||
Globals.key_linepos = 1;
|
||||
if (Globals.cls.state == Defines.ca_disconnected)
|
||||
SCR.UpdateScreen(); // force an update, because the command may take some time
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_TAB) {
|
||||
// command completion
|
||||
CompleteCommand();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((key == K_BACKSPACE) || (key == K_LEFTARROW) || (key == K_KP_LEFTARROW) || ((key == 'h') && (Globals.keydown[K_CTRL]))) {
|
||||
if (Globals.key_linepos > 1)
|
||||
Globals.key_linepos--;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((key == K_UPARROW) || (key == K_KP_UPARROW) || ((key == 'p') && Globals.keydown[K_CTRL])) {
|
||||
do {
|
||||
history_line = (history_line - 1) & 31;
|
||||
}
|
||||
while (history_line != Globals.edit_line && Globals.key_lines[history_line][1] == 0);
|
||||
if (history_line == Globals.edit_line)
|
||||
history_line = (Globals.edit_line + 1) & 31;
|
||||
//Lib.strcpy(Globals.key_lines[Globals.edit_line], Globals.key_lines[history_line]);
|
||||
System.arraycopy(Globals.key_lines[history_line], 0, Globals.key_lines[Globals.edit_line], 0, Globals.key_lines[Globals.edit_line].length);
|
||||
Globals.key_linepos = Lib.strlen(Globals.key_lines[Globals.edit_line]);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((key == K_DOWNARROW) || (key == K_KP_DOWNARROW) || ((key == 'n') && Globals.keydown[K_CTRL])) {
|
||||
if (history_line == Globals.edit_line)
|
||||
return;
|
||||
do {
|
||||
history_line = (history_line + 1) & 31;
|
||||
}
|
||||
while (history_line != Globals.edit_line && Globals.key_lines[history_line][1] == 0);
|
||||
if (history_line == Globals.edit_line) {
|
||||
Globals.key_lines[Globals.edit_line][0] = ']';
|
||||
Globals.key_linepos = 1;
|
||||
}
|
||||
else {
|
||||
//Lib.strcpy(Globals.key_lines[Globals.edit_line], Globals.key_lines[history_line]);
|
||||
System.arraycopy(Globals.key_lines[history_line], 0, Globals.key_lines[Globals.edit_line], 0, Globals.key_lines[Globals.edit_line].length);
|
||||
Globals.key_linepos = Lib.strlen(Globals.key_lines[Globals.edit_line]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_PGUP || key == K_KP_PGUP) {
|
||||
Globals.con.display -= 2;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_PGDN || key == K_KP_PGDN) {
|
||||
Globals.con.display += 2;
|
||||
if (Globals.con.display > Globals.con.current)
|
||||
Globals.con.display = Globals.con.current;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_HOME || key == K_KP_HOME) {
|
||||
Globals.con.display = Globals.con.current - Globals.con.totallines + 10;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_END || key == K_KP_END) {
|
||||
Globals.con.display = Globals.con.current;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key < 32 || key > 127)
|
||||
return; // non printable
|
||||
|
||||
if (Globals.key_linepos < Defines.MAXCMDLINE - 1) {
|
||||
Globals.key_lines[Globals.edit_line][Globals.key_linepos] = (byte) key;
|
||||
Globals.key_linepos++;
|
||||
Globals.key_lines[Globals.edit_line][Globals.key_linepos] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void printCompletions(String type, Vector<String> compl) {
|
||||
StringBuilder sb = new StringBuilder(compl.size());
|
||||
for (int i = 0; i < compl.size(); i++) {
|
||||
sb.append(compl.get(i)).append(' ');
|
||||
}
|
||||
//TODO потом убрать
|
||||
while (type.startsWith("\n")) { type = type.substring(1); }
|
||||
while (type.endsWith("\n")) { type = type.substring(0, type.lastIndexOf("\n")); }
|
||||
while (type.endsWith("\r")) { type = type.substring(0, type.lastIndexOf("\r")); }
|
||||
type = type.trim();
|
||||
log.info("{} {}", type, sb.toString());
|
||||
}
|
||||
|
||||
static void CompleteCommand() {
|
||||
|
||||
int start = 1;
|
||||
if (key_lines[edit_line][start] == '\\' || key_lines[edit_line][start] == '/')
|
||||
start++;
|
||||
|
||||
int end = start;
|
||||
while (key_lines[edit_line][end] != 0) end++;
|
||||
|
||||
String s = new String(key_lines[edit_line], start, end-start);
|
||||
|
||||
Vector<String> cmds = Cmd.CompleteCommand(s);
|
||||
Vector<String> vars = Cvar.CompleteVariable(s);
|
||||
|
||||
int c = cmds.size();
|
||||
int v = vars.size();
|
||||
|
||||
if ((c + v) > 1) {
|
||||
if (c > 0) printCompletions("\nCommands:\n", cmds);
|
||||
if (v > 0) printCompletions("\nVariables:\n", vars);
|
||||
return;
|
||||
} else if (c == 1) {
|
||||
s = (String)cmds.get(0);
|
||||
} else if (v == 1) {
|
||||
s = (String)vars.get(0);
|
||||
} else return;
|
||||
|
||||
key_lines[edit_line][1] = '/';
|
||||
byte[] bytes = Lib.stringToBytes(s);
|
||||
System.arraycopy(bytes, 0, key_lines[edit_line], 2, bytes.length);
|
||||
key_linepos = bytes.length + 2;
|
||||
key_lines[edit_line][key_linepos++] = ' ';
|
||||
key_lines[edit_line][key_linepos] = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public static Runnable Bind_f = Key::Key_Bind_f;
|
||||
|
||||
static void Key_Bind_f() {
|
||||
int c = Cmd.Argc();
|
||||
|
||||
if (c < 2) {
|
||||
Com.Printf("bind <key> [command] : attach a command to a key\n");
|
||||
return;
|
||||
}
|
||||
int b = StringToKeynum(Cmd.Argv(1));
|
||||
if (b == -1) {
|
||||
Com.Printf("\"" + Cmd.Argv(1) + "\" isn't a valid key\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == 2) {
|
||||
if (Globals.keybindings[b] != null)
|
||||
Com.Printf("\"" + Cmd.Argv(1) + "\" = \"" + Globals.keybindings[b] + "\"\n");
|
||||
else
|
||||
Com.Printf("\"" + Cmd.Argv(1) + "\" is not bound\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// copy the rest of the command line
|
||||
String cmd = ""; // start out with a null string
|
||||
for (int i = 2; i < c; i++) {
|
||||
cmd += Cmd.Argv(i);
|
||||
if (i != (c - 1))
|
||||
cmd += " ";
|
||||
}
|
||||
|
||||
SetBinding(b, cmd);
|
||||
}
|
||||
|
||||
static void SetBinding(int keynum, String binding) {
|
||||
if (keynum == -1)
|
||||
return;
|
||||
|
||||
// free old bindings
|
||||
Globals.keybindings[keynum] = null;
|
||||
|
||||
Globals.keybindings[keynum] = binding;
|
||||
}
|
||||
|
||||
static Runnable Unbind_f = Key::Key_Unbind_f;
|
||||
|
||||
static void Key_Unbind_f() {
|
||||
|
||||
if (Cmd.Argc() != 2) {
|
||||
Com.Printf("unbind <key> : remove commands from a key\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int b = Key.StringToKeynum(Cmd.Argv(1));
|
||||
if (b == -1) {
|
||||
Com.Printf("\"" + Cmd.Argv(1) + "\" isn't a valid key\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Key.SetBinding(b, null);
|
||||
}
|
||||
|
||||
static Runnable Unbindall_f = Key::Key_Unbindall_f;
|
||||
|
||||
static void Key_Unbindall_f() {
|
||||
for (int i = 0; i < 256; i++)
|
||||
Key.SetBinding(i, null);
|
||||
}
|
||||
|
||||
static Runnable Bindlist_f = Key::Key_Bindlist_f;
|
||||
|
||||
static void Key_Bindlist_f() {
|
||||
for (int i = 0; i < 256; i++)
|
||||
if (Globals.keybindings[i] != null && Globals.keybindings[i].length() != 0)
|
||||
Com.Printf(Key.KeynumToString(i) + " \"" + Globals.keybindings[i] + "\"\n");
|
||||
}
|
||||
|
||||
static void ClearStates() {
|
||||
int i;
|
||||
|
||||
Key.anykeydown = 0;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (keydown[i] || key_repeats[i]!=0)
|
||||
Event(i, false, 0);
|
||||
keydown[i] = false;
|
||||
key_repeats[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteBindings(RandomAccessFile f) {
|
||||
for (int i = 0; i < 256; i++)
|
||||
if (keybindings[i] != null && keybindings[i].length() > 0)
|
||||
try {
|
||||
f.writeBytes("bind " + KeynumToString(i) + " \"" + keybindings[i] + "\"\n");
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
}
|
||||
495
src/main/java/lwjake2/client/M.java
Normal file
495
src/main/java/lwjake2/client/M.java
Normal file
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.game.EntThinkAdapter;
|
||||
import lwjake2.game.GameBase;
|
||||
import lwjake2.game.GameCombat;
|
||||
import lwjake2.game.edict_t;
|
||||
import lwjake2.game.mmove_t;
|
||||
import lwjake2.game.trace_t;
|
||||
import lwjake2.server.SV;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
/**
|
||||
* M
|
||||
*/
|
||||
public final class M {
|
||||
|
||||
public static void M_CheckGround(edict_t ent) {
|
||||
float[] point = { 0, 0, 0 };
|
||||
trace_t trace;
|
||||
|
||||
if ((ent.flags & (Defines.FL_SWIM | Defines.FL_FLY)) != 0)
|
||||
return;
|
||||
|
||||
if (ent.velocity[2] > 100) {
|
||||
ent.groundentity = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// if the hull point one-quarter unit down is solid the entity is on
|
||||
// ground
|
||||
point[0] = ent.s.origin[0];
|
||||
point[1] = ent.s.origin[1];
|
||||
point[2] = ent.s.origin[2] - 0.25f;
|
||||
|
||||
trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, point, ent,
|
||||
Defines.MASK_MONSTERSOLID);
|
||||
|
||||
// check steepness
|
||||
if (trace.plane.normal[2] < 0.7 && !trace.startsolid) {
|
||||
ent.groundentity = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// ent.groundentity = trace.ent;
|
||||
// ent.groundentity_linkcount = trace.ent.linkcount;
|
||||
// if (!trace.startsolid && !trace.allsolid)
|
||||
// VectorCopy (trace.endpos, ent.s.origin);
|
||||
if (!trace.startsolid && !trace.allsolid) {
|
||||
Math3D.VectorCopy(trace.endpos, ent.s.origin);
|
||||
ent.groundentity = trace.ent;
|
||||
ent.groundentity_linkcount = trace.ent.linkcount;
|
||||
ent.velocity[2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if any part of the bottom of the entity is off an edge that
|
||||
* is not a staircase.
|
||||
*/
|
||||
|
||||
public static boolean M_CheckBottom(edict_t ent) {
|
||||
float[] mins = { 0, 0, 0 };
|
||||
float[] maxs = { 0, 0, 0 };
|
||||
float[] start = { 0, 0, 0 };
|
||||
float[] stop = { 0, 0, 0 };
|
||||
|
||||
trace_t trace;
|
||||
int x, y;
|
||||
float mid, bottom;
|
||||
|
||||
Math3D.VectorAdd(ent.s.origin, ent.mins, mins);
|
||||
Math3D.VectorAdd(ent.s.origin, ent.maxs, maxs);
|
||||
|
||||
// if all of the points under the corners are solid world, don't bother
|
||||
// with the tougher checks
|
||||
// the corners must be within 16 of the midpoint
|
||||
start[2] = mins[2] - 1;
|
||||
for (x = 0; x <= 1; x++)
|
||||
for (y = 0; y <= 1; y++) {
|
||||
start[0] = x != 0 ? maxs[0] : mins[0];
|
||||
start[1] = y != 0 ? maxs[1] : mins[1];
|
||||
if (GameBase.gi.pointcontents.pointcontents(start) != Defines.CONTENTS_SOLID) {
|
||||
GameBase.c_no++;
|
||||
//
|
||||
// check it for real...
|
||||
//
|
||||
start[2] = mins[2];
|
||||
|
||||
// the midpoint must be within 16 of the bottom
|
||||
start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5f;
|
||||
start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5f;
|
||||
stop[2] = start[2] - 2 * GameBase.STEPSIZE;
|
||||
trace = GameBase.gi.trace(start, Globals.vec3_origin,
|
||||
Globals.vec3_origin, stop, ent,
|
||||
Defines.MASK_MONSTERSOLID);
|
||||
|
||||
if (trace.fraction == 1.0)
|
||||
return false;
|
||||
mid = bottom = trace.endpos[2];
|
||||
|
||||
// the corners must be within 16 of the midpoint
|
||||
for (x = 0; x <= 1; x++)
|
||||
for (y = 0; y <= 1; y++) {
|
||||
start[0] = stop[0] = x != 0 ? maxs[0] : mins[0];
|
||||
start[1] = stop[1] = y != 0 ? maxs[1] : mins[1];
|
||||
|
||||
trace = GameBase.gi.trace(start,
|
||||
Globals.vec3_origin, Globals.vec3_origin,
|
||||
stop, ent, Defines.MASK_MONSTERSOLID);
|
||||
|
||||
if (trace.fraction != 1.0
|
||||
&& trace.endpos[2] > bottom)
|
||||
bottom = trace.endpos[2];
|
||||
if (trace.fraction == 1.0
|
||||
|| mid - trace.endpos[2] > GameBase.STEPSIZE)
|
||||
return false;
|
||||
}
|
||||
|
||||
GameBase.c_yes++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
GameBase.c_yes++;
|
||||
return true; // we got out easy
|
||||
}
|
||||
|
||||
/**
|
||||
* M_ChangeYaw.
|
||||
*/
|
||||
public static void M_ChangeYaw(edict_t ent) {
|
||||
float ideal;
|
||||
float current;
|
||||
float move;
|
||||
float speed;
|
||||
|
||||
current = Math3D.anglemod(ent.s.angles[Defines.YAW]);
|
||||
ideal = ent.ideal_yaw;
|
||||
|
||||
if (current == ideal)
|
||||
return;
|
||||
|
||||
move = ideal - current;
|
||||
speed = ent.yaw_speed;
|
||||
if (ideal > current) {
|
||||
if (move >= 180)
|
||||
move = move - 360;
|
||||
} else {
|
||||
if (move <= -180)
|
||||
move = move + 360;
|
||||
}
|
||||
if (move > 0) {
|
||||
if (move > speed)
|
||||
move = speed;
|
||||
} else {
|
||||
if (move < -speed)
|
||||
move = -speed;
|
||||
}
|
||||
|
||||
ent.s.angles[Defines.YAW] = Math3D.anglemod(current + move);
|
||||
}
|
||||
|
||||
/**
|
||||
* M_MoveToGoal.
|
||||
*/
|
||||
public static void M_MoveToGoal(edict_t ent, float dist) {
|
||||
edict_t goal = ent.goalentity;
|
||||
|
||||
if (ent.groundentity == null
|
||||
&& (ent.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == 0)
|
||||
return;
|
||||
|
||||
// if the next step hits the enemy, return immediately
|
||||
if (ent.enemy != null && SV.SV_CloseEnough(ent, ent.enemy, dist))
|
||||
return;
|
||||
|
||||
// bump around...
|
||||
if ((Lib.rand() & 3) == 1
|
||||
|| !SV.SV_StepDirection(ent, ent.ideal_yaw, dist)) {
|
||||
if (ent.inuse)
|
||||
SV.SV_NewChaseDir(ent, goal, dist);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* M_walkmove.
|
||||
*/
|
||||
public static boolean M_walkmove(edict_t ent, float yaw, float dist) {
|
||||
float[] move = { 0, 0, 0 };
|
||||
|
||||
if ((ent.groundentity == null)
|
||||
&& (ent.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == 0)
|
||||
return false;
|
||||
|
||||
yaw = (float) (yaw * Math.PI * 2 / 360);
|
||||
|
||||
move[0] = (float) Math.cos(yaw) * dist;
|
||||
move[1] = (float) Math.sin(yaw) * dist;
|
||||
move[2] = 0;
|
||||
|
||||
return SV.SV_movestep(ent, move, true);
|
||||
}
|
||||
|
||||
public static void M_CatagorizePosition(edict_t ent) {
|
||||
float[] point = { 0, 0, 0 };
|
||||
int cont;
|
||||
|
||||
//
|
||||
// get waterlevel
|
||||
//
|
||||
point[0] = ent.s.origin[0];
|
||||
point[1] = ent.s.origin[1];
|
||||
point[2] = ent.s.origin[2] + ent.mins[2] + 1;
|
||||
cont = GameBase.gi.pointcontents.pointcontents(point);
|
||||
|
||||
if (0 == (cont & Defines.MASK_WATER)) {
|
||||
ent.waterlevel = 0;
|
||||
ent.watertype = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ent.watertype = cont;
|
||||
ent.waterlevel = 1;
|
||||
point[2] += 26;
|
||||
cont = GameBase.gi.pointcontents.pointcontents(point);
|
||||
if (0 == (cont & Defines.MASK_WATER))
|
||||
return;
|
||||
|
||||
ent.waterlevel = 2;
|
||||
point[2] += 22;
|
||||
cont = GameBase.gi.pointcontents.pointcontents(point);
|
||||
if (0 != (cont & Defines.MASK_WATER))
|
||||
ent.waterlevel = 3;
|
||||
}
|
||||
|
||||
public static void M_WorldEffects(edict_t ent) {
|
||||
int dmg;
|
||||
|
||||
if (ent.health > 0) {
|
||||
if (0 == (ent.flags & Defines.FL_SWIM)) {
|
||||
if (ent.waterlevel < 3) {
|
||||
ent.air_finished = GameBase.level.time + 12;
|
||||
} else if (ent.air_finished < GameBase.level.time) {
|
||||
// drown!
|
||||
if (ent.pain_debounce_time < GameBase.level.time) {
|
||||
dmg = (int) (2f + 2f * Math.floor(GameBase.level.time
|
||||
- ent.air_finished));
|
||||
if (dmg > 15)
|
||||
dmg = 15;
|
||||
GameCombat.T_Damage(ent, GameBase.g_edicts[0],
|
||||
GameBase.g_edicts[0], Globals.vec3_origin,
|
||||
ent.s.origin, Globals.vec3_origin, dmg, 0,
|
||||
Defines.DAMAGE_NO_ARMOR, Defines.MOD_WATER);
|
||||
ent.pain_debounce_time = GameBase.level.time + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ent.waterlevel > 0) {
|
||||
ent.air_finished = GameBase.level.time + 9;
|
||||
} else if (ent.air_finished < GameBase.level.time) {
|
||||
// suffocate!
|
||||
if (ent.pain_debounce_time < GameBase.level.time) {
|
||||
dmg = (int) (2 + 2 * Math.floor(GameBase.level.time
|
||||
- ent.air_finished));
|
||||
if (dmg > 15)
|
||||
dmg = 15;
|
||||
GameCombat.T_Damage(ent, GameBase.g_edicts[0],
|
||||
GameBase.g_edicts[0], Globals.vec3_origin,
|
||||
ent.s.origin, Globals.vec3_origin, dmg, 0,
|
||||
Defines.DAMAGE_NO_ARMOR, Defines.MOD_WATER);
|
||||
ent.pain_debounce_time = GameBase.level.time + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ent.waterlevel == 0) {
|
||||
if ((ent.flags & Defines.FL_INWATER) != 0) {
|
||||
GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi
|
||||
.soundindex("player/watr_out.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
ent.flags &= ~Defines.FL_INWATER;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ent.watertype & Defines.CONTENTS_LAVA) != 0
|
||||
&& 0 == (ent.flags & Defines.FL_IMMUNE_LAVA)) {
|
||||
if (ent.damage_debounce_time < GameBase.level.time) {
|
||||
ent.damage_debounce_time = GameBase.level.time + 0.2f;
|
||||
GameCombat.T_Damage(ent, GameBase.g_edicts[0],
|
||||
GameBase.g_edicts[0], Globals.vec3_origin,
|
||||
ent.s.origin, Globals.vec3_origin, 10 * ent.waterlevel,
|
||||
0, 0, Defines.MOD_LAVA);
|
||||
}
|
||||
}
|
||||
if ((ent.watertype & Defines.CONTENTS_SLIME) != 0
|
||||
&& 0 == (ent.flags & Defines.FL_IMMUNE_SLIME)) {
|
||||
if (ent.damage_debounce_time < GameBase.level.time) {
|
||||
ent.damage_debounce_time = GameBase.level.time + 1;
|
||||
GameCombat.T_Damage(ent, GameBase.g_edicts[0],
|
||||
GameBase.g_edicts[0], Globals.vec3_origin,
|
||||
ent.s.origin, Globals.vec3_origin, 4 * ent.waterlevel,
|
||||
0, 0, Defines.MOD_SLIME);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == (ent.flags & Defines.FL_INWATER)) {
|
||||
if (0 == (ent.svflags & Defines.SVF_DEADMONSTER)) {
|
||||
if ((ent.watertype & Defines.CONTENTS_LAVA) != 0)
|
||||
if (Globals.rnd.nextFloat() <= 0.5)
|
||||
GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi
|
||||
.soundindex("player/lava1.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
else
|
||||
GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi
|
||||
.soundindex("player/lava2.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
else if ((ent.watertype & Defines.CONTENTS_SLIME) != 0)
|
||||
GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi
|
||||
.soundindex("player/watr_in.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
else if ((ent.watertype & Defines.CONTENTS_WATER) != 0)
|
||||
GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi
|
||||
.soundindex("player/watr_in.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
ent.flags |= Defines.FL_INWATER;
|
||||
ent.damage_debounce_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static EntThinkAdapter M_droptofloor = new EntThinkAdapter() {
|
||||
public String getID() { return "m_drop_to_floor";}
|
||||
public boolean think(edict_t ent) {
|
||||
float[] end = { 0, 0, 0 };
|
||||
trace_t trace;
|
||||
|
||||
ent.s.origin[2] += 1;
|
||||
Math3D.VectorCopy(ent.s.origin, end);
|
||||
end[2] -= 256;
|
||||
|
||||
trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, end,
|
||||
ent, Defines.MASK_MONSTERSOLID);
|
||||
|
||||
if (trace.fraction == 1 || trace.allsolid)
|
||||
return true;
|
||||
|
||||
Math3D.VectorCopy(trace.endpos, ent.s.origin);
|
||||
|
||||
GameBase.gi.linkentity(ent);
|
||||
M.M_CheckGround(ent);
|
||||
M_CatagorizePosition(ent);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static void M_SetEffects(edict_t ent) {
|
||||
ent.s.effects &= ~(Defines.EF_COLOR_SHELL | Defines.EF_POWERSCREEN);
|
||||
ent.s.renderfx &= ~(Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE);
|
||||
|
||||
if ((ent.monsterinfo.aiflags & Defines.AI_RESURRECTING) != 0) {
|
||||
ent.s.effects |= Defines.EF_COLOR_SHELL;
|
||||
ent.s.renderfx |= Defines.RF_SHELL_RED;
|
||||
}
|
||||
|
||||
if (ent.health <= 0)
|
||||
return;
|
||||
|
||||
if (ent.powerarmor_time > GameBase.level.time) {
|
||||
if (ent.monsterinfo.power_armor_type == Defines.POWER_ARMOR_SCREEN) {
|
||||
ent.s.effects |= Defines.EF_POWERSCREEN;
|
||||
} else if (ent.monsterinfo.power_armor_type == Defines.POWER_ARMOR_SHIELD) {
|
||||
ent.s.effects |= Defines.EF_COLOR_SHELL;
|
||||
ent.s.renderfx |= Defines.RF_SHELL_GREEN;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//ok
|
||||
public static void M_MoveFrame(edict_t self) {
|
||||
mmove_t move; //ptr
|
||||
int index;
|
||||
|
||||
move = self.monsterinfo.currentmove;
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
|
||||
if ((self.monsterinfo.nextframe != 0)
|
||||
&& (self.monsterinfo.nextframe >= move.firstframe)
|
||||
&& (self.monsterinfo.nextframe <= move.lastframe)) {
|
||||
self.s.frame = self.monsterinfo.nextframe;
|
||||
self.monsterinfo.nextframe = 0;
|
||||
} else {
|
||||
if (self.s.frame == move.lastframe) {
|
||||
if (move.endfunc != null) {
|
||||
move.endfunc.think(self);
|
||||
|
||||
// regrab move, endfunc is very likely to change it
|
||||
move = self.monsterinfo.currentmove;
|
||||
|
||||
// check for death
|
||||
if ((self.svflags & Defines.SVF_DEADMONSTER) != 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (self.s.frame < move.firstframe || self.s.frame > move.lastframe) {
|
||||
self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME;
|
||||
self.s.frame = move.firstframe;
|
||||
} else {
|
||||
if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME)) {
|
||||
self.s.frame++;
|
||||
if (self.s.frame > move.lastframe)
|
||||
self.s.frame = move.firstframe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index = self.s.frame - move.firstframe;
|
||||
if (move.frame[index].ai != null)
|
||||
if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME))
|
||||
move.frame[index].ai.ai(self, move.frame[index].dist
|
||||
* self.monsterinfo.scale);
|
||||
else
|
||||
move.frame[index].ai.ai(self, 0);
|
||||
|
||||
if (move.frame[index].think != null)
|
||||
move.frame[index].think.think(self);
|
||||
}
|
||||
|
||||
/** Stops the Flies. */
|
||||
public static EntThinkAdapter M_FliesOff = new EntThinkAdapter() {
|
||||
public String getID() { return "m_fliesoff";}
|
||||
public boolean think(edict_t self) {
|
||||
self.s.effects &= ~Defines.EF_FLIES;
|
||||
self.s.sound = 0;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/** Starts the Flies as setting the animation flag in the entity. */
|
||||
public static EntThinkAdapter M_FliesOn = new EntThinkAdapter() {
|
||||
public String getID() { return "m_flies_on";}
|
||||
public boolean think(edict_t self) {
|
||||
if (self.waterlevel != 0)
|
||||
return true;
|
||||
|
||||
self.s.effects |= Defines.EF_FLIES;
|
||||
self.s.sound = GameBase.gi.soundindex("infantry/inflies1.wav");
|
||||
self.think = M_FliesOff;
|
||||
self.nextthink = GameBase.level.time + 60;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/** Adds some flies after a random time */
|
||||
public static EntThinkAdapter M_FlyCheck = new EntThinkAdapter() {
|
||||
public String getID() { return "m_fly_check";}
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
if (self.waterlevel != 0)
|
||||
return true;
|
||||
|
||||
if (Globals.rnd.nextFloat() > 0.5)
|
||||
return true;
|
||||
|
||||
self.think = M_FliesOn;
|
||||
self.nextthink = GameBase.level.time + 5 + 10
|
||||
* Globals.rnd.nextFloat();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
4264
src/main/java/lwjake2/client/Menu.java
Normal file
4264
src/main/java/lwjake2/client/Menu.java
Normal file
File diff suppressed because it is too large
Load Diff
1834
src/main/java/lwjake2/client/SCR.java
Normal file
1834
src/main/java/lwjake2/client/SCR.java
Normal file
File diff suppressed because it is too large
Load Diff
397
src/main/java/lwjake2/client/V.java
Normal file
397
src/main/java/lwjake2/client/V.java
Normal file
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.game.Cmd;
|
||||
import lwjake2.game.cvar_t;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.qcommon.Cvar;
|
||||
import lwjake2.sys.Timer;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* V
|
||||
*/
|
||||
@Slf4j
|
||||
public final class V extends Globals {
|
||||
static cvar_t cl_testblend;
|
||||
|
||||
static cvar_t cl_testparticles;
|
||||
|
||||
static cvar_t cl_testentities;
|
||||
|
||||
static cvar_t cl_testlights;
|
||||
|
||||
static cvar_t cl_stats;
|
||||
|
||||
static int r_numdlights;
|
||||
|
||||
static dlight_t[] r_dlights = new dlight_t[MAX_DLIGHTS];
|
||||
|
||||
static int r_numentities;
|
||||
|
||||
static entity_t[] r_entities = new entity_t[MAX_ENTITIES];
|
||||
|
||||
static int r_numparticles;
|
||||
|
||||
//static particle_t[] r_particles = new particle_t[MAX_PARTICLES];
|
||||
|
||||
static lightstyle_t[] r_lightstyles = new lightstyle_t[MAX_LIGHTSTYLES];
|
||||
static {
|
||||
for (int i = 0; i < r_dlights.length; i++)
|
||||
r_dlights[i] = new dlight_t();
|
||||
for (int i = 0; i < r_entities.length; i++)
|
||||
r_entities[i] = new entity_t();
|
||||
for (int i = 0; i < r_lightstyles.length; i++)
|
||||
r_lightstyles[i] = new lightstyle_t();
|
||||
}
|
||||
|
||||
/*
|
||||
* ==================== V_ClearScene
|
||||
*
|
||||
* Specifies the model that will be used as the world ====================
|
||||
*/
|
||||
static void ClearScene() {
|
||||
r_numdlights = 0;
|
||||
r_numentities = 0;
|
||||
r_numparticles = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===================== V_AddEntity
|
||||
*
|
||||
* =====================
|
||||
*/
|
||||
static void AddEntity(entity_t ent) {
|
||||
if (r_numentities >= MAX_ENTITIES)
|
||||
return;
|
||||
r_entities[r_numentities++].set(ent);
|
||||
}
|
||||
|
||||
/*
|
||||
* ===================== V_AddParticle
|
||||
*
|
||||
* =====================
|
||||
*/
|
||||
static void AddParticle(float[] org, int color, float alpha) {
|
||||
if (r_numparticles >= MAX_PARTICLES)
|
||||
return;
|
||||
|
||||
int i = r_numparticles++;
|
||||
|
||||
int c = particle_t.colorTable[color];
|
||||
c |= (int) (alpha * 255) << 24;
|
||||
particle_t.colorArray.put(i, c);
|
||||
|
||||
i *= 3;
|
||||
FloatBuffer vertexBuf = particle_t.vertexArray;
|
||||
vertexBuf.put(i++, org[0]);
|
||||
vertexBuf.put(i++, org[1]);
|
||||
vertexBuf.put(i++, org[2]);
|
||||
}
|
||||
|
||||
/*
|
||||
* ===================== V_AddLight
|
||||
*
|
||||
* =====================
|
||||
*/
|
||||
static void AddLight(float[] org, float intensity, float r, float g, float b) {
|
||||
dlight_t dl;
|
||||
|
||||
if (r_numdlights >= MAX_DLIGHTS)
|
||||
return;
|
||||
dl = r_dlights[r_numdlights++];
|
||||
Math3D.VectorCopy(org, dl.origin);
|
||||
dl.intensity = intensity;
|
||||
dl.color[0] = r;
|
||||
dl.color[1] = g;
|
||||
dl.color[2] = b;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===================== V_AddLightStyle
|
||||
*
|
||||
* =====================
|
||||
*/
|
||||
static void AddLightStyle(int style, float r, float g, float b) {
|
||||
lightstyle_t ls;
|
||||
|
||||
if (style < 0 || style > MAX_LIGHTSTYLES)
|
||||
Com.Error(ERR_DROP, "Bad light style " + style);
|
||||
ls = r_lightstyles[style];
|
||||
|
||||
ls.white = r + g + b;
|
||||
ls.rgb[0] = r;
|
||||
ls.rgb[1] = g;
|
||||
ls.rgb[2] = b;
|
||||
}
|
||||
|
||||
// stack variable
|
||||
private static final float[] origin = { 0, 0, 0 };
|
||||
/*
|
||||
* ================ V_TestParticles
|
||||
*
|
||||
* If cl_testparticles is set, create 4096 particles in the view
|
||||
* ================
|
||||
*/
|
||||
static void TestParticles() {
|
||||
int i, j;
|
||||
float d, r, u;
|
||||
|
||||
r_numparticles = 0;
|
||||
for (i = 0; i < MAX_PARTICLES; i++) {
|
||||
d = i * 0.25f;
|
||||
r = 4 * ((i & 7) - 3.5f);
|
||||
u = 4 * (((i >> 3) & 7) - 3.5f);
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j] * d
|
||||
+ cl.v_right[j] * r + cl.v_up[j] * u;
|
||||
|
||||
AddParticle(origin, 8, cl_testparticles.value);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ V_TestEntities
|
||||
*
|
||||
* If cl_testentities is set, create 32 player models ================
|
||||
*/
|
||||
static void TestEntities() {
|
||||
int i, j;
|
||||
float f, r;
|
||||
entity_t ent;
|
||||
|
||||
r_numentities = 32;
|
||||
//memset (r_entities, 0, sizeof(r_entities));
|
||||
for (i = 0; i < r_entities.length; i++)
|
||||
r_entities[i].clear();
|
||||
|
||||
for (i = 0; i < r_numentities; i++) {
|
||||
ent = r_entities[i];
|
||||
|
||||
r = 64 * ((i % 4) - 1.5f);
|
||||
f = 64 * (i / 4) + 128;
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
ent.origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j] * f
|
||||
+ cl.v_right[j] * r;
|
||||
|
||||
ent.model = cl.baseclientinfo.model;
|
||||
ent.skin = cl.baseclientinfo.skin;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ V_TestLights
|
||||
*
|
||||
* If cl_testlights is set, create 32 lights models ================
|
||||
*/
|
||||
static void TestLights() {
|
||||
int i, j;
|
||||
float f, r;
|
||||
dlight_t dl;
|
||||
|
||||
r_numdlights = 32;
|
||||
//memset (r_dlights, 0, sizeof(r_dlights));
|
||||
for (i = 0; i < r_dlights.length; i++)
|
||||
r_dlights[i] = new dlight_t();
|
||||
|
||||
for (i = 0; i < r_numdlights; i++) {
|
||||
dl = r_dlights[i];
|
||||
|
||||
r = 64 * ((i % 4) - 1.5f);
|
||||
f = 64 * (i / 4) + 128;
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
dl.origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j] * f
|
||||
+ cl.v_right[j] * r;
|
||||
dl.color[0] = ((i % 6) + 1) & 1;
|
||||
dl.color[1] = (((i % 6) + 1) & 2) >> 1;
|
||||
dl.color[2] = (((i % 6) + 1) & 4) >> 2;
|
||||
dl.intensity = 200;
|
||||
}
|
||||
}
|
||||
|
||||
static Runnable Gun_Next_f = () -> {
|
||||
gun_frame++;
|
||||
Com.Printf("frame " + gun_frame + "\n");
|
||||
};
|
||||
|
||||
static Runnable Gun_Prev_f = () -> {
|
||||
gun_frame--;
|
||||
if (gun_frame < 0)
|
||||
gun_frame = 0;
|
||||
Com.Printf("frame " + gun_frame + "\n");
|
||||
};
|
||||
|
||||
static Runnable Gun_Model_f = () -> {
|
||||
if (Cmd.Argc() != 2) {
|
||||
gun_model = null;
|
||||
return;
|
||||
}
|
||||
String name = "models/" + Cmd.Argv(1) + "/tris.md2";
|
||||
gun_model = re.RegisterModel(name);
|
||||
};
|
||||
|
||||
/*
|
||||
* ================== V_RenderView
|
||||
*
|
||||
* ==================
|
||||
*/
|
||||
static void RenderView(float stereo_separation) {
|
||||
// extern int entitycmpfnc( const entity_t *, const entity_t * );
|
||||
//
|
||||
if (cls.state != ca_active)
|
||||
return;
|
||||
|
||||
if (!cl.refresh_prepped)
|
||||
return; // still loading
|
||||
|
||||
if (cl_timedemo.value != 0.0f) {
|
||||
if (cl.timedemo_start == 0)
|
||||
cl.timedemo_start = Timer.Milliseconds();
|
||||
cl.timedemo_frames++;
|
||||
}
|
||||
|
||||
// an invalid frame will just use the exact previous refdef
|
||||
// we can't use the old frame if the video mode has changed, though...
|
||||
if (cl.frame.valid && (cl.force_refdef || cl_paused.value == 0.0f)) {
|
||||
cl.force_refdef = false;
|
||||
|
||||
V.ClearScene();
|
||||
|
||||
// build a refresh entity list and calc cl.sim*
|
||||
// this also calls CL_CalcViewValues which loads
|
||||
// v_forward, etc.
|
||||
CL_ents.AddEntities();
|
||||
|
||||
if (cl_testparticles.value != 0.0f)
|
||||
TestParticles();
|
||||
if (cl_testentities.value != 0.0f)
|
||||
TestEntities();
|
||||
if (cl_testlights.value != 0.0f)
|
||||
TestLights();
|
||||
if (cl_testblend.value != 0.0f) {
|
||||
cl.refdef.blend[0] = 1.0f;
|
||||
cl.refdef.blend[1] = 0.5f;
|
||||
cl.refdef.blend[2] = 0.25f;
|
||||
cl.refdef.blend[3] = 0.5f;
|
||||
}
|
||||
|
||||
// offset vieworg appropriately if we're doing stereo separation
|
||||
if (stereo_separation != 0) {
|
||||
float[] tmp = new float[3];
|
||||
|
||||
Math3D.VectorScale(cl.v_right, stereo_separation, tmp);
|
||||
Math3D.VectorAdd(cl.refdef.vieworg, tmp, cl.refdef.vieworg);
|
||||
}
|
||||
|
||||
// never let it sit exactly on a node line, because a water plane
|
||||
// can
|
||||
// dissapear when viewed with the eye exactly on it.
|
||||
// the server protocol only specifies to 1/8 pixel, so add 1/16 in
|
||||
// each axis
|
||||
cl.refdef.vieworg[0] += 1.0 / 16;
|
||||
cl.refdef.vieworg[1] += 1.0 / 16;
|
||||
cl.refdef.vieworg[2] += 1.0 / 16;
|
||||
|
||||
cl.refdef.x = scr_vrect.x;
|
||||
cl.refdef.y = scr_vrect.y;
|
||||
cl.refdef.width = scr_vrect.width;
|
||||
cl.refdef.height = scr_vrect.height;
|
||||
cl.refdef.fov_y = Math3D.CalcFov(cl.refdef.fov_x, cl.refdef.width,
|
||||
cl.refdef.height);
|
||||
cl.refdef.time = cl.time * 0.001f;
|
||||
|
||||
cl.refdef.areabits = cl.frame.areabits;
|
||||
|
||||
if (cl_add_entities.value == 0.0f)
|
||||
r_numentities = 0;
|
||||
if (cl_add_particles.value == 0.0f)
|
||||
r_numparticles = 0;
|
||||
if (cl_add_lights.value == 0.0f)
|
||||
r_numdlights = 0;
|
||||
if (cl_add_blend.value == 0) {
|
||||
Math3D.VectorClear(cl.refdef.blend);
|
||||
}
|
||||
|
||||
cl.refdef.num_entities = r_numentities;
|
||||
cl.refdef.entities = r_entities;
|
||||
cl.refdef.num_particles = r_numparticles;
|
||||
cl.refdef.num_dlights = r_numdlights;
|
||||
cl.refdef.dlights = r_dlights;
|
||||
cl.refdef.lightstyles = r_lightstyles;
|
||||
|
||||
cl.refdef.rdflags = cl.frame.playerstate.rdflags;
|
||||
|
||||
// sort entities for better cache locality
|
||||
// !!! useless in Java !!!
|
||||
//Arrays.sort(cl.refdef.entities, entitycmpfnc);
|
||||
}
|
||||
|
||||
re.RenderFrame(cl.refdef);
|
||||
if (cl_stats.value != 0.0f)
|
||||
log.info("ent:{} lt:{} part:{}", r_numentities, r_numdlights, r_numparticles);
|
||||
if (log_stats.value != 0.0f && (log_stats_file != null))
|
||||
try {
|
||||
log_stats_file.write(r_numentities + "," + r_numdlights + ","
|
||||
+ r_numparticles);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
|
||||
SCR.AddDirtyPoint(scr_vrect.x, scr_vrect.y);
|
||||
SCR.AddDirtyPoint(scr_vrect.x + scr_vrect.width - 1, scr_vrect.y
|
||||
+ scr_vrect.height - 1);
|
||||
|
||||
SCR.DrawCrosshair();
|
||||
}
|
||||
|
||||
/*
|
||||
* ============= V_Viewpos_f =============
|
||||
*/
|
||||
static Runnable Viewpos_f = () -> log.info("({} {} {}) : {}",
|
||||
(int) cl.refdef.vieworg[0],
|
||||
(int) cl.refdef.vieworg[1],
|
||||
(int) cl.refdef.vieworg[2],
|
||||
(int) cl.refdef.viewangles[YAW]
|
||||
);
|
||||
|
||||
public static void Init() {
|
||||
Cmd.AddCommand("gun_next", Gun_Next_f);
|
||||
Cmd.AddCommand("gun_prev", Gun_Prev_f);
|
||||
Cmd.AddCommand("gun_model", Gun_Model_f);
|
||||
|
||||
Cmd.AddCommand("viewpos", Viewpos_f);
|
||||
|
||||
crosshair = Cvar.Get("crosshair", "0", CVAR_ARCHIVE);
|
||||
|
||||
cl_testblend = Cvar.Get("cl_testblend", "0", 0);
|
||||
cl_testparticles = Cvar.Get("cl_testparticles", "0", 0);
|
||||
cl_testentities = Cvar.Get("cl_testentities", "0", 0);
|
||||
cl_testlights = Cvar.Get("cl_testlights", "0", 0);
|
||||
|
||||
cl_stats = Cvar.Get("cl_stats", "0", 0);
|
||||
}
|
||||
}
|
||||
746
src/main/java/lwjake2/client/VID.java
Normal file
746
src/main/java/lwjake2/client/VID.java
Normal file
@@ -0,0 +1,746 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.game.Cmd;
|
||||
import lwjake2.game.cvar_t;
|
||||
import lwjake2.qcommon.Callback;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.qcommon.Cvar;
|
||||
import lwjake2.render.Renderer;
|
||||
import lwjake2.sound.S;
|
||||
import lwjake2.sys.IN;
|
||||
import lwjake2.util.Vargs;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.DisplayMode;
|
||||
|
||||
/**
|
||||
* VID is a video driver.
|
||||
*
|
||||
* source: client/vid.h linux/vid_so.c
|
||||
*
|
||||
* @author cwei
|
||||
*/
|
||||
@Slf4j
|
||||
public class VID extends Globals {
|
||||
// Main windowed and fullscreen graphics interface module. This module
|
||||
// is used for both the software and OpenGL rendering versions of the
|
||||
// Quake refresh engine.
|
||||
|
||||
// Global variables used internally by this module
|
||||
// Globals.viddef
|
||||
// global video state; used by other modules
|
||||
|
||||
// Structure containing functions exported from refresh DLL
|
||||
// Globals.re;
|
||||
|
||||
// Console variables that we need to access from this module
|
||||
static cvar_t vid_gamma;
|
||||
static cvar_t vid_ref; // Name of Refresh DLL loaded
|
||||
static cvar_t vid_xpos; // X coordinate of window position
|
||||
static cvar_t vid_ypos; // Y coordinate of window position
|
||||
static cvar_t vid_width;
|
||||
static cvar_t vid_height;
|
||||
static cvar_t vid_fullscreen;
|
||||
|
||||
// Global variables used internally by this module
|
||||
// void *reflib_library; // Handle to refresh DLL
|
||||
static boolean reflib_active = false;
|
||||
// const char so_file[] = "/etc/quake2.conf";
|
||||
|
||||
/*
|
||||
==========================================================================
|
||||
|
||||
DLL GLUE
|
||||
|
||||
==========================================================================
|
||||
*/
|
||||
|
||||
public static void Printf(int print_level, String fmt) {
|
||||
while (fmt.startsWith("\n")) { fmt = fmt.substring(1); }
|
||||
while (fmt.endsWith("\n")) { fmt = fmt.substring(0, fmt.lastIndexOf("\n")); }
|
||||
while (fmt.endsWith("\r")) { fmt = fmt.substring(0, fmt.lastIndexOf("\r")); }
|
||||
fmt = fmt.trim();
|
||||
log.warn("{}", fmt);
|
||||
}
|
||||
|
||||
public static void Printf(int print_level, String fmt, Vargs vargs) {
|
||||
// static qboolean inupdate;
|
||||
if (print_level == Defines.PRINT_ALL)
|
||||
Com.Printf(fmt, vargs);
|
||||
else
|
||||
Com.DPrintf(fmt, vargs);
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
|
||||
/*
|
||||
============
|
||||
VID_Restart_f
|
||||
|
||||
Console command to re-start the video mode and refresh DLL. We do this
|
||||
simply by setting the modified flag for the vid_ref variable, which will
|
||||
cause the entire video mode and refresh DLL to be reset on the next frame.
|
||||
============
|
||||
*/
|
||||
static void Restart_f() {
|
||||
vid_modes[11].width = (int) vid_width.value;
|
||||
vid_modes[11].height = (int) vid_height.value;
|
||||
|
||||
vid_ref.modified = true;
|
||||
}
|
||||
|
||||
/*
|
||||
** VID_GetModeInfo
|
||||
*/
|
||||
static vidmode_t vid_modes[] =
|
||||
{
|
||||
new vidmode_t("Mode 0: 320x240", 320, 240, 0),
|
||||
new vidmode_t("Mode 1: 400x300", 400, 300, 1),
|
||||
new vidmode_t("Mode 2: 512x384", 512, 384, 2),
|
||||
new vidmode_t("Mode 3: 640x480", 640, 480, 3),
|
||||
new vidmode_t("Mode 4: 800x600", 800, 600, 4),
|
||||
new vidmode_t("Mode 5: 960x720", 960, 720, 5),
|
||||
new vidmode_t("Mode 6: 1024x768", 1024, 768, 6),
|
||||
new vidmode_t("Mode 7: 1152x864", 1152, 864, 7),
|
||||
new vidmode_t("Mode 8: 1280x1024", 1280, 1024, 8),
|
||||
new vidmode_t("Mode 9: 1600x1200", 1600, 1200, 9),
|
||||
new vidmode_t("Mode 10: 2048x1536", 2048, 1536, 10),
|
||||
new vidmode_t("Mode 11: user", 640, 480, 11)};
|
||||
static vidmode_t fs_modes[];
|
||||
|
||||
public static boolean GetModeInfo(Dimension dim, int mode) {
|
||||
if (fs_modes == null) initModeList();
|
||||
|
||||
vidmode_t[] modes = vid_modes;
|
||||
if (vid_fullscreen.value != 0.0f) modes = fs_modes;
|
||||
|
||||
if (mode < 0 || mode >= modes.length)
|
||||
return false;
|
||||
|
||||
dim.width = modes[mode].width;
|
||||
dim.height = modes[mode].height;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
** VID_NewWindow
|
||||
*/
|
||||
public static void NewWindow(int width, int height) {
|
||||
Globals.viddef.width = width;
|
||||
Globals.viddef.height = height;
|
||||
}
|
||||
|
||||
static void FreeReflib()
|
||||
{
|
||||
if (Globals.re != null) {
|
||||
Globals.re.getKeyboardHandler().Close();
|
||||
IN.Shutdown();
|
||||
}
|
||||
|
||||
Globals.re = null;
|
||||
reflib_active = false;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
VID_LoadRefresh
|
||||
==============
|
||||
*/
|
||||
static boolean LoadRefresh( String name )
|
||||
{
|
||||
|
||||
if ( reflib_active )
|
||||
{
|
||||
Globals.re.getKeyboardHandler().Close();
|
||||
IN.Shutdown();
|
||||
|
||||
Globals.re.Shutdown();
|
||||
FreeReflib();
|
||||
}
|
||||
|
||||
log.info("------- Loading {} -------", name);
|
||||
|
||||
|
||||
boolean found = false;
|
||||
|
||||
String[] driverNames = Renderer.getDriverNames();
|
||||
for (int i = 0; i < driverNames.length; i++) {
|
||||
if (driverNames[i].equals(name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
log.warn("LoadLibrary(\"{}\") failed", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info("LoadLibrary(\"{}\")", name);
|
||||
Globals.re = Renderer.getDriver(name);
|
||||
|
||||
if (Globals.re == null)
|
||||
{
|
||||
Com.Error(Defines.ERR_FATAL, name + " can't load but registered");
|
||||
}
|
||||
|
||||
if (Globals.re.apiVersion() != Defines.API_VERSION)
|
||||
{
|
||||
FreeReflib();
|
||||
Com.Error(Defines.ERR_FATAL, name + " has incompatible api_version");
|
||||
}
|
||||
|
||||
IN.Real_IN_Init();
|
||||
|
||||
if ( !Globals.re.Init((int)vid_xpos.value, (int)vid_ypos.value) )
|
||||
{
|
||||
Globals.re.Shutdown();
|
||||
FreeReflib();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Init KBD */
|
||||
Globals.re.getKeyboardHandler().Init();
|
||||
|
||||
log.info("------------------------------------");
|
||||
reflib_active = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
VID_CheckChanges
|
||||
|
||||
This function gets called once just before drawing each frame, and it's sole purpose in life
|
||||
is to check to see if any of the video mode parameters have changed, and if they have to
|
||||
update the rendering DLL and/or video mode to match.
|
||||
============
|
||||
*/
|
||||
public static void CheckChanges()
|
||||
{
|
||||
cvar_t gl_mode;
|
||||
|
||||
if ( vid_ref.modified )
|
||||
{
|
||||
S.StopAllSounds();
|
||||
}
|
||||
|
||||
while (vid_ref.modified)
|
||||
{
|
||||
/*
|
||||
** refresh has changed
|
||||
*/
|
||||
vid_ref.modified = false;
|
||||
vid_fullscreen.modified = true;
|
||||
Globals.cl.refresh_prepped = false;
|
||||
Globals.cls.disable_screen = 1.0f; // true;
|
||||
|
||||
|
||||
if ( !LoadRefresh( vid_ref.string ) )
|
||||
{
|
||||
String renderer;
|
||||
if (vid_ref.string.equals(Renderer.getPreferedName())) {
|
||||
// try the default renderer as fallback after prefered
|
||||
renderer = Renderer.getDefaultName();
|
||||
} else {
|
||||
// try the prefered renderer as first fallback
|
||||
renderer = Renderer.getPreferedName();
|
||||
}
|
||||
if ( vid_ref.string.equals(Renderer.getDefaultName())) {
|
||||
renderer = vid_ref.string;
|
||||
log.info("Refresh failed");
|
||||
gl_mode = Cvar.Get( "gl_mode", "0", 0 );
|
||||
if (gl_mode.value != 0.0f) {
|
||||
log.info("Trying mode 0");
|
||||
Cvar.SetValue("gl_mode", 0);
|
||||
if ( !LoadRefresh( vid_ref.string ) )
|
||||
Com.Error(Defines.ERR_FATAL, "Couldn't fall back to " + renderer +" refresh!");
|
||||
} else
|
||||
Com.Error(Defines.ERR_FATAL, "Couldn't fall back to " + renderer +" refresh!");
|
||||
}
|
||||
|
||||
Cvar.Set("vid_ref", renderer);
|
||||
|
||||
/*
|
||||
* drop the console if we fail to load a refresh
|
||||
*/
|
||||
if ( Globals.cls.key_dest != Defines.key_console )
|
||||
{
|
||||
try {
|
||||
Console.ToggleConsole_f.run();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Globals.cls.disable_screen = 0.0f; //false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
VID_Init
|
||||
============
|
||||
*/
|
||||
public static void Init()
|
||||
{
|
||||
/* Create the video variables so we know how to start the graphics drivers */
|
||||
vid_ref = Cvar.Get("vid_ref", Renderer.getPreferedName(), CVAR_ARCHIVE);
|
||||
vid_xpos = Cvar.Get("vid_xpos", "3", CVAR_ARCHIVE);
|
||||
vid_ypos = Cvar.Get("vid_ypos", "22", CVAR_ARCHIVE);
|
||||
vid_width = Cvar.Get("vid_width", "640", CVAR_ARCHIVE);
|
||||
vid_height = Cvar.Get("vid_height", "480", CVAR_ARCHIVE);
|
||||
vid_fullscreen = Cvar.Get("vid_fullscreen", "0", CVAR_ARCHIVE);
|
||||
vid_gamma = Cvar.Get( "vid_gamma", "1", CVAR_ARCHIVE );
|
||||
|
||||
vid_modes[11].width = (int)vid_width.value;
|
||||
vid_modes[11].height = (int)vid_height.value;
|
||||
|
||||
/* Add some console commands that we want to handle */
|
||||
Cmd.AddCommand ("vid_restart", VID::Restart_f);
|
||||
|
||||
/* Disable the 3Dfx splash screen */
|
||||
// putenv("FX_GLIDE_NO_SPLASH=0");
|
||||
|
||||
/* Start the graphics mode and load refresh DLL */
|
||||
CheckChanges();
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
VID_Shutdown
|
||||
============
|
||||
*/
|
||||
public static void Shutdown()
|
||||
{
|
||||
if ( reflib_active )
|
||||
{
|
||||
Globals.re.getKeyboardHandler().Close();
|
||||
IN.Shutdown();
|
||||
|
||||
Globals.re.Shutdown();
|
||||
FreeReflib();
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
//
|
||||
// vid_menu.c
|
||||
//
|
||||
// ==========================================================================
|
||||
|
||||
static final int REF_OPENGL_JOGL = 0;
|
||||
static final int REF_OPENGL_FASTJOGL =1;
|
||||
static final int REF_OPENGL_LWJGL =2;
|
||||
|
||||
static cvar_t gl_mode;
|
||||
static cvar_t gl_driver;
|
||||
static cvar_t gl_picmip;
|
||||
static cvar_t gl_ext_palettedtexture;
|
||||
|
||||
static cvar_t sw_mode;
|
||||
static cvar_t sw_stipplealpha;
|
||||
|
||||
static cvar_t _windowed_mouse;
|
||||
|
||||
/*
|
||||
====================================================================
|
||||
|
||||
MENU INTERACTION
|
||||
|
||||
====================================================================
|
||||
*/
|
||||
|
||||
static Menu.menuframework_s s_opengl_menu = new Menu.menuframework_s();
|
||||
static Menu.menuframework_s s_current_menu; // referenz
|
||||
|
||||
static Menu.menulist_s s_mode_list = new Menu.menulist_s();
|
||||
|
||||
static Menu.menulist_s s_ref_list = new Menu.menulist_s();
|
||||
|
||||
static Menu.menuslider_s s_tq_slider = new Menu.menuslider_s();
|
||||
static Menu.menuslider_s s_screensize_slider = new Menu.menuslider_s();
|
||||
|
||||
static Menu.menuslider_s s_brightness_slider = new Menu.menuslider_s();
|
||||
|
||||
static Menu.menulist_s s_fs_box = new Menu.menulist_s();
|
||||
|
||||
static Menu.menulist_s s_stipple_box = new Menu.menulist_s();
|
||||
static Menu.menulist_s s_paletted_texture_box = new Menu.menulist_s();
|
||||
static Menu.menulist_s s_windowed_mouse = new Menu.menulist_s();
|
||||
static Menu.menuaction_s s_apply_action = new Menu.menuaction_s();
|
||||
|
||||
static Menu.menuaction_s s_defaults_action= new Menu.menuaction_s();
|
||||
|
||||
static void DriverCallback( Object unused )
|
||||
{
|
||||
s_current_menu = s_opengl_menu; // s_software_menu;
|
||||
}
|
||||
|
||||
static void ScreenSizeCallback( Object s )
|
||||
{
|
||||
Menu.menuslider_s slider = (Menu.menuslider_s) s;
|
||||
|
||||
Cvar.SetValue( "viewsize", slider.curvalue * 10 );
|
||||
}
|
||||
|
||||
static void BrightnessCallback( Object s )
|
||||
{
|
||||
Menu.menuslider_s slider = (Menu.menuslider_s) s;
|
||||
|
||||
// if ( stricmp( vid_ref.string, "soft" ) == 0 ||
|
||||
// stricmp( vid_ref.string, "softx" ) == 0 )
|
||||
if ( vid_ref.string.equalsIgnoreCase("soft") ||
|
||||
vid_ref.string.equalsIgnoreCase("softx") )
|
||||
{
|
||||
float gamma = ( 0.8f - ( slider.curvalue/10.0f - 0.5f ) ) + 0.5f;
|
||||
|
||||
Cvar.SetValue( "vid_gamma", gamma );
|
||||
}
|
||||
}
|
||||
|
||||
static void ResetDefaults( Object unused )
|
||||
{
|
||||
MenuInit();
|
||||
}
|
||||
|
||||
static void ApplyChanges( Object unused )
|
||||
{
|
||||
|
||||
/*
|
||||
** invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
|
||||
*/
|
||||
// the original was modified, because on CRTs it was too dark.
|
||||
// the slider range is [5; 13]
|
||||
// gamma: [1.1; 0.7]
|
||||
float gamma = ( 0.4f - ( s_brightness_slider.curvalue/20.0f - 0.25f ) ) + 0.7f;
|
||||
// modulate: [1.0; 2.6]
|
||||
float modulate = s_brightness_slider.curvalue * 0.2f;
|
||||
|
||||
Cvar.SetValue( "vid_gamma", gamma );
|
||||
Cvar.SetValue( "gl_modulate", modulate);
|
||||
Cvar.SetValue( "sw_stipplealpha", s_stipple_box.curvalue );
|
||||
Cvar.SetValue( "gl_picmip", 3 - s_tq_slider.curvalue );
|
||||
Cvar.SetValue( "vid_fullscreen", s_fs_box.curvalue );
|
||||
Cvar.SetValue( "gl_ext_palettedtexture", s_paletted_texture_box.curvalue );
|
||||
Cvar.SetValue( "gl_mode", s_mode_list.curvalue );
|
||||
Cvar.SetValue( "_windowed_mouse", s_windowed_mouse.curvalue);
|
||||
|
||||
Cvar.Set( "vid_ref", drivers[s_ref_list.curvalue] );
|
||||
Cvar.Set( "gl_driver", drivers[s_ref_list.curvalue] );
|
||||
if (gl_driver.modified)
|
||||
vid_ref.modified = true;
|
||||
|
||||
Menu.ForceMenuOff();
|
||||
}
|
||||
|
||||
static final String[] resolutions =
|
||||
{
|
||||
"[320 240 ]",
|
||||
"[400 300 ]",
|
||||
"[512 384 ]",
|
||||
"[640 480 ]",
|
||||
"[800 600 ]",
|
||||
"[960 720 ]",
|
||||
"[1024 768 ]",
|
||||
"[1152 864 ]",
|
||||
"[1280 1024]",
|
||||
"[1600 1200]",
|
||||
"[2048 1536]",
|
||||
"user mode",
|
||||
};
|
||||
static String[] fs_resolutions;
|
||||
static int mode_x;
|
||||
|
||||
static String[] refs;
|
||||
static String[] drivers;
|
||||
|
||||
static final String[] yesno_names =
|
||||
{
|
||||
"no",
|
||||
"yes",
|
||||
};
|
||||
|
||||
static void initModeList() {
|
||||
DisplayMode[] modes = re.getModeList();
|
||||
fs_resolutions = new String[modes.length];
|
||||
fs_modes = new vidmode_t[modes.length];
|
||||
for (int i = 0; i < modes.length; i++) {
|
||||
DisplayMode m = modes[i];
|
||||
StringBuffer sb = new StringBuffer(18);
|
||||
sb.append('[');
|
||||
sb.append(m.getWidth());
|
||||
sb.append(' ');
|
||||
sb.append(m.getHeight());
|
||||
while (sb.length() < 10) sb.append(' ');
|
||||
sb.append(']');
|
||||
fs_resolutions[i] = sb.toString();
|
||||
sb.setLength(0);
|
||||
sb.append("Mode ");
|
||||
sb.append(i);
|
||||
sb.append(':');
|
||||
sb.append(m.getWidth());
|
||||
sb.append('x');
|
||||
sb.append(m.getHeight());
|
||||
fs_modes[i] = new vidmode_t(sb.toString(), m.getWidth(), m.getHeight(), i);
|
||||
}
|
||||
}
|
||||
|
||||
private static void initRefs() {
|
||||
drivers = Renderer.getDriverNames();
|
||||
refs = new String[drivers.length];
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < drivers.length; i++) {
|
||||
sb.setLength(0);
|
||||
sb.append("[OpenGL ").append(drivers[i]);
|
||||
while (sb.length() < 16) sb.append(" ");
|
||||
sb.append("]");
|
||||
refs[i] = sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** VID_MenuInit
|
||||
*/
|
||||
public static void MenuInit() {
|
||||
|
||||
initRefs();
|
||||
|
||||
if ( gl_driver == null )
|
||||
gl_driver = Cvar.Get( "gl_driver", Renderer.getPreferedName(), 0 );
|
||||
if ( gl_picmip == null )
|
||||
gl_picmip = Cvar.Get( "gl_picmip", "0", 0 );
|
||||
if ( gl_mode == null)
|
||||
gl_mode = Cvar.Get( "gl_mode", "3", 0 );
|
||||
if ( sw_mode == null )
|
||||
sw_mode = Cvar.Get( "sw_mode", "0", 0 );
|
||||
if ( gl_ext_palettedtexture == null )
|
||||
gl_ext_palettedtexture = Cvar.Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE );
|
||||
|
||||
if ( sw_stipplealpha == null )
|
||||
sw_stipplealpha = Cvar.Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
|
||||
|
||||
if ( _windowed_mouse == null)
|
||||
_windowed_mouse = Cvar.Get( "_windowed_mouse", "0", CVAR_ARCHIVE );
|
||||
|
||||
s_mode_list.curvalue = (int)gl_mode.value;
|
||||
if (vid_fullscreen.value != 0.0f) {
|
||||
s_mode_list.itemnames = fs_resolutions;
|
||||
if (s_mode_list.curvalue >= fs_resolutions.length - 1) {
|
||||
s_mode_list.curvalue = 0;
|
||||
}
|
||||
mode_x = fs_modes[s_mode_list.curvalue].width;
|
||||
} else {
|
||||
s_mode_list.itemnames = resolutions;
|
||||
if (s_mode_list.curvalue >= resolutions.length - 1) {
|
||||
s_mode_list.curvalue = 0;
|
||||
}
|
||||
mode_x = vid_modes[s_mode_list.curvalue].width;
|
||||
}
|
||||
|
||||
if ( SCR.scr_viewsize == null )
|
||||
SCR.scr_viewsize = Cvar.Get ("viewsize", "100", CVAR_ARCHIVE);
|
||||
|
||||
s_screensize_slider.curvalue = (int)(SCR.scr_viewsize.value/10);
|
||||
|
||||
for (int i = 0; i < drivers.length; i++) {
|
||||
if (vid_ref.string.equals(drivers[i])) {
|
||||
s_ref_list.curvalue = i;
|
||||
}
|
||||
}
|
||||
|
||||
s_opengl_menu.x = (int)(viddef.width * 0.50f);
|
||||
s_opengl_menu.nitems = 0;
|
||||
|
||||
s_ref_list.type = MTYPE_SPINCONTROL;
|
||||
s_ref_list.name = "driver";
|
||||
s_ref_list.x = 0;
|
||||
s_ref_list.y = 0;
|
||||
s_ref_list.callback = VID::DriverCallback;
|
||||
s_ref_list.itemnames = refs;
|
||||
|
||||
s_mode_list.type = MTYPE_SPINCONTROL;
|
||||
s_mode_list.name = "video mode";
|
||||
s_mode_list.x = 0;
|
||||
s_mode_list.y = 10;
|
||||
|
||||
s_screensize_slider.type = MTYPE_SLIDER;
|
||||
s_screensize_slider.x = 0;
|
||||
s_screensize_slider.y = 20;
|
||||
s_screensize_slider.name = "screen size";
|
||||
s_screensize_slider.minvalue = 3;
|
||||
s_screensize_slider.maxvalue = 12;
|
||||
s_screensize_slider.callback = VID::ScreenSizeCallback;
|
||||
s_brightness_slider.type = MTYPE_SLIDER;
|
||||
s_brightness_slider.x = 0;
|
||||
s_brightness_slider.y = 30;
|
||||
s_brightness_slider.name = "brightness";
|
||||
s_brightness_slider.callback = VID::BrightnessCallback;
|
||||
s_brightness_slider.minvalue = 5;
|
||||
s_brightness_slider.maxvalue = 13;
|
||||
s_brightness_slider.curvalue = ( 1.3f - vid_gamma.value + 0.5f ) * 10;
|
||||
|
||||
s_fs_box.type = MTYPE_SPINCONTROL;
|
||||
s_fs_box.x = 0;
|
||||
s_fs_box.y = 40;
|
||||
s_fs_box.name = "fullscreen";
|
||||
s_fs_box.itemnames = yesno_names;
|
||||
s_fs_box.curvalue = (int)vid_fullscreen.value;
|
||||
s_fs_box.callback = o -> {
|
||||
int fs = ((Menu.menulist_s)o).curvalue;
|
||||
if (fs == 0) {
|
||||
s_mode_list.itemnames = resolutions;
|
||||
int i = vid_modes.length - 2;
|
||||
while (i > 0 && vid_modes[i].width > mode_x) i--;
|
||||
s_mode_list.curvalue = i;
|
||||
} else {
|
||||
s_mode_list.itemnames = fs_resolutions;
|
||||
int i = fs_modes.length - 1;
|
||||
while (i > 0 && fs_modes[i].width > mode_x) i--;
|
||||
s_mode_list.curvalue = i;
|
||||
}
|
||||
};
|
||||
|
||||
s_defaults_action.type = MTYPE_ACTION;
|
||||
s_defaults_action.name = "reset to default";
|
||||
s_defaults_action.x = 0;
|
||||
s_defaults_action.y = 90;
|
||||
s_defaults_action.callback = VID::ResetDefaults;
|
||||
|
||||
s_apply_action.type = MTYPE_ACTION;
|
||||
s_apply_action.name = "apply";
|
||||
s_apply_action.x = 0;
|
||||
s_apply_action.y = 100;
|
||||
s_apply_action.callback = VID::ApplyChanges;
|
||||
|
||||
|
||||
s_stipple_box.type = MTYPE_SPINCONTROL;
|
||||
s_stipple_box.x = 0;
|
||||
s_stipple_box.y = 60;
|
||||
s_stipple_box.name = "stipple alpha";
|
||||
s_stipple_box.curvalue = (int)sw_stipplealpha.value;
|
||||
s_stipple_box.itemnames = yesno_names;
|
||||
|
||||
s_windowed_mouse.type = MTYPE_SPINCONTROL;
|
||||
s_windowed_mouse.x = 0;
|
||||
s_windowed_mouse.y = 72;
|
||||
s_windowed_mouse.name = "windowed mouse";
|
||||
s_windowed_mouse.curvalue = (int)_windowed_mouse.value;
|
||||
s_windowed_mouse.itemnames = yesno_names;
|
||||
|
||||
s_tq_slider.type = MTYPE_SLIDER;
|
||||
s_tq_slider.x = 0;
|
||||
s_tq_slider.y = 60;
|
||||
s_tq_slider.name = "texture quality";
|
||||
s_tq_slider.minvalue = 0;
|
||||
s_tq_slider.maxvalue = 3;
|
||||
s_tq_slider.curvalue = 3 - gl_picmip.value;
|
||||
|
||||
s_paletted_texture_box.type = MTYPE_SPINCONTROL;
|
||||
s_paletted_texture_box.x = 0;
|
||||
s_paletted_texture_box.y = 70;
|
||||
s_paletted_texture_box.name = "8-bit textures";
|
||||
s_paletted_texture_box.itemnames = yesno_names;
|
||||
s_paletted_texture_box.curvalue = (int)gl_ext_palettedtexture.value;
|
||||
|
||||
Menu.Menu_AddItem( s_opengl_menu, s_ref_list );
|
||||
Menu.Menu_AddItem( s_opengl_menu, s_mode_list );
|
||||
Menu.Menu_AddItem( s_opengl_menu, s_screensize_slider );
|
||||
Menu.Menu_AddItem( s_opengl_menu, s_brightness_slider );
|
||||
Menu.Menu_AddItem( s_opengl_menu, s_fs_box );
|
||||
Menu.Menu_AddItem( s_opengl_menu, s_tq_slider );
|
||||
Menu.Menu_AddItem( s_opengl_menu, s_paletted_texture_box );
|
||||
|
||||
Menu.Menu_AddItem( s_opengl_menu, s_defaults_action );
|
||||
Menu.Menu_AddItem( s_opengl_menu, s_apply_action );
|
||||
|
||||
Menu.Menu_Center( s_opengl_menu );
|
||||
s_opengl_menu.x -= 8;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
VID_MenuDraw
|
||||
================
|
||||
*/
|
||||
static void MenuDraw()
|
||||
{
|
||||
s_current_menu = s_opengl_menu;
|
||||
|
||||
/*
|
||||
** draw the banner
|
||||
*/
|
||||
Dimension dim = new Dimension();
|
||||
re.DrawGetPicSize( dim, "m_banner_video" );
|
||||
re.DrawPic( viddef.width / 2 - dim.width / 2, viddef.height /2 - 110, "m_banner_video" );
|
||||
|
||||
/*
|
||||
** move cursor to a reasonable starting position
|
||||
*/
|
||||
Menu.Menu_AdjustCursor( s_current_menu, 1 );
|
||||
|
||||
/*
|
||||
** draw the menu
|
||||
*/
|
||||
Menu.Menu_Draw( s_current_menu );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
VID_MenuKey
|
||||
================
|
||||
*/
|
||||
static String MenuKey( int key )
|
||||
{
|
||||
Menu.menuframework_s m = s_current_menu;
|
||||
final String sound = "misc/menu1.wav";
|
||||
|
||||
switch ( key )
|
||||
{
|
||||
case K_ESCAPE:
|
||||
Menu.PopMenu();
|
||||
return null;
|
||||
case K_UPARROW:
|
||||
m.cursor--;
|
||||
Menu.Menu_AdjustCursor( m, -1 );
|
||||
break;
|
||||
case K_DOWNARROW:
|
||||
m.cursor++;
|
||||
Menu.Menu_AdjustCursor( m, 1 );
|
||||
break;
|
||||
case K_LEFTARROW:
|
||||
Menu.Menu_SlideItem( m, -1 );
|
||||
break;
|
||||
case K_RIGHTARROW:
|
||||
Menu.Menu_SlideItem( m, 1 );
|
||||
break;
|
||||
case K_ENTER:
|
||||
Menu.Menu_SelectItem( m );
|
||||
break;
|
||||
}
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
}
|
||||
34
src/main/java/lwjake2/client/centity_t.java
Normal file
34
src/main/java/lwjake2/client/centity_t.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.game.entity_state_t;
|
||||
|
||||
public class centity_t {
|
||||
entity_state_t baseline= new entity_state_t(null); // delta from this if not from a previous frame
|
||||
public entity_state_t current= new entity_state_t(null);
|
||||
entity_state_t prev= new entity_state_t(null); // will always be valid, but might just be a copy of current
|
||||
|
||||
int serverframe; // if not current, this ent isn't in the frame
|
||||
|
||||
int trailcount; // for diminishing grenade trails
|
||||
float[] lerp_origin = { 0, 0, 0 }; // for trails (variable hz)
|
||||
|
||||
int fly_stoptime;
|
||||
}
|
||||
48
src/main/java/lwjake2/client/cl_sustain_t.java
Normal file
48
src/main/java/lwjake2/client/cl_sustain_t.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
/**
|
||||
* cl_sustain_t
|
||||
*/
|
||||
public class cl_sustain_t {
|
||||
static abstract class ThinkAdapter {
|
||||
abstract void think(cl_sustain_t self);
|
||||
}
|
||||
|
||||
int id;
|
||||
int type;
|
||||
int endtime;
|
||||
int nextthink;
|
||||
int thinkinterval;
|
||||
float[] org = new float[3];
|
||||
float[] dir = new float[3];
|
||||
int color;
|
||||
int count;
|
||||
int magnitude;
|
||||
|
||||
ThinkAdapter think;
|
||||
|
||||
void clear() {
|
||||
org[0] = org[1] = org[2] =
|
||||
dir[0] = dir[1] = dir[2] =
|
||||
id = type = endtime = nextthink = thinkinterval = color = count = magnitude = 0;
|
||||
think = null;
|
||||
}
|
||||
}
|
||||
133
src/main/java/lwjake2/client/client_state_t.java
Normal file
133
src/main/java/lwjake2/client/client_state_t.java
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.game.cmodel_t;
|
||||
import lwjake2.game.usercmd_t;
|
||||
import lwjake2.render.image_t;
|
||||
import lwjake2.render.model_t;
|
||||
import lwjake2.sound.sfx_t;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class client_state_t {
|
||||
|
||||
public client_state_t() {
|
||||
for (int n = 0; n < Defines.CMD_BACKUP; n++)
|
||||
cmds[n] = new usercmd_t();
|
||||
for (int i = 0; i < frames.length; i++) {
|
||||
frames[i] = new frame_t();
|
||||
}
|
||||
|
||||
for (int n = 0; n < Defines.MAX_CONFIGSTRINGS; n++)
|
||||
configstrings[n] = new String();
|
||||
|
||||
for (int n=0; n < Defines.MAX_CLIENTS; n++)
|
||||
clientinfo[n] = new clientinfo_t();
|
||||
}
|
||||
//
|
||||
// the client_state_t structure is wiped completely at every
|
||||
// server map change
|
||||
//
|
||||
int timeoutcount;
|
||||
|
||||
int timedemo_frames;
|
||||
int timedemo_start;
|
||||
|
||||
public boolean refresh_prepped; // false if on new level or new ref dll
|
||||
public boolean sound_prepped; // ambient sounds can start
|
||||
boolean force_refdef; // vid has changed, so we can't use a paused refdef
|
||||
|
||||
int parse_entities; // index (not anded off) into cl_parse_entities[]
|
||||
|
||||
usercmd_t cmd = new usercmd_t();
|
||||
usercmd_t cmds[] = new usercmd_t[Defines.CMD_BACKUP]; // each mesage will send several old cmds
|
||||
|
||||
int cmd_time[] = new int[Defines.CMD_BACKUP]; // time sent, for calculating pings
|
||||
short predicted_origins[][] = new short[Defines.CMD_BACKUP][3]; // for debug comparing against server
|
||||
|
||||
float predicted_step; // for stair up smoothing
|
||||
int predicted_step_time;
|
||||
|
||||
float[] predicted_origin ={0,0,0}; // generated by CL_PredictMovement
|
||||
float[] predicted_angles={0,0,0};
|
||||
float[] prediction_error={0,0,0};
|
||||
|
||||
public frame_t frame = new frame_t(); // received from server
|
||||
int surpressCount; // number of messages rate supressed
|
||||
frame_t frames[] = new frame_t[Defines.UPDATE_BACKUP];
|
||||
|
||||
// the client maintains its own idea of view angles, which are
|
||||
// sent to the server each frame. It is cleared to 0 upon entering each level.
|
||||
// the server sends a delta each frame which is added to the locally
|
||||
// tracked view angles to account for standing on rotating objects,
|
||||
// and teleport direction changes
|
||||
public float[] viewangles = { 0, 0, 0 };
|
||||
|
||||
public int time; // this is the time value that the client
|
||||
// is rendering at. always <= cls.realtime
|
||||
float lerpfrac; // between oldframe and frame
|
||||
|
||||
refdef_t refdef = new refdef_t();
|
||||
|
||||
float[] v_forward = { 0, 0, 0 };
|
||||
float[] v_right = { 0, 0, 0 };
|
||||
float[] v_up = { 0, 0, 0 }; // set when refdef.angles is set
|
||||
|
||||
//
|
||||
// transient data from server
|
||||
//
|
||||
|
||||
String layout = ""; // general 2D overlay
|
||||
int inventory[] = new int[Defines.MAX_ITEMS];
|
||||
|
||||
//
|
||||
// non-gameserver infornamtion
|
||||
// FIXME: move this cinematic stuff into the cin_t structure
|
||||
ByteBuffer cinematic_file;
|
||||
|
||||
int cinematictime; // cls.realtime for first cinematic frame
|
||||
int cinematicframe;
|
||||
byte cinematicpalette[] = new byte[768];
|
||||
boolean cinematicpalette_active;
|
||||
|
||||
//
|
||||
// server state information
|
||||
//
|
||||
boolean attractloop; // running the attract loop, any key will menu
|
||||
int servercount; // server identification for prespawns
|
||||
String gamedir ="";
|
||||
public int playernum;
|
||||
|
||||
public String configstrings[] = new String[Defines.MAX_CONFIGSTRINGS];
|
||||
|
||||
//
|
||||
// locally derived information from server state
|
||||
//
|
||||
model_t model_draw[] = new model_t[Defines.MAX_MODELS];
|
||||
cmodel_t model_clip[] = new cmodel_t[Defines.MAX_MODELS];
|
||||
|
||||
public sfx_t sound_precache[] = new sfx_t[Defines.MAX_SOUNDS];
|
||||
image_t image_precache[] = new image_t[Defines.MAX_IMAGES];
|
||||
|
||||
clientinfo_t clientinfo[] = new clientinfo_t[Defines.MAX_CLIENTS];
|
||||
clientinfo_t baseclientinfo = new clientinfo_t();
|
||||
|
||||
}
|
||||
67
src/main/java/lwjake2/client/client_static_t.java
Normal file
67
src/main/java/lwjake2/client/client_static_t.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.qcommon.netchan_t;
|
||||
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public class client_static_t {
|
||||
|
||||
// was enum connstate_t
|
||||
public int state;
|
||||
|
||||
// was enum keydest_t
|
||||
public int key_dest;
|
||||
|
||||
public int framecount;
|
||||
public int realtime; // always increasing, no clamping, etc
|
||||
public float frametime; // seconds since last frame
|
||||
|
||||
// screen rendering information
|
||||
public float disable_screen; // showing loading plaque between levels
|
||||
// or changing rendering dlls
|
||||
// if time gets > 30 seconds ahead, break it
|
||||
public int disable_servercount; // when we receive a frame and cl.servercount
|
||||
// > cls.disable_servercount, clear disable_screen
|
||||
|
||||
// connection information
|
||||
public String servername = ""; // name of server from original connect
|
||||
public float connect_time; // for connection retransmits
|
||||
|
||||
int quakePort; // a 16 bit value that allows quake servers
|
||||
// to work around address translating routers
|
||||
public netchan_t netchan = new netchan_t();
|
||||
public int serverProtocol; // in case we are doing some kind of version hack
|
||||
|
||||
public int challenge; // from the server to use for connecting
|
||||
|
||||
public RandomAccessFile download; // file transfer from server
|
||||
public String downloadtempname="";
|
||||
public String downloadname="";
|
||||
public int downloadnumber;
|
||||
// was enum dltype_t
|
||||
public int downloadtype;
|
||||
public int downloadpercent;
|
||||
|
||||
// demo recording info must be here, so it isn't cleared on level change
|
||||
public boolean demorecording;
|
||||
public boolean demowaiting; // don't record until a non-delta message is received
|
||||
public RandomAccessFile demofile;
|
||||
}
|
||||
49
src/main/java/lwjake2/client/clientinfo_t.java
Normal file
49
src/main/java/lwjake2/client/clientinfo_t.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.render.image_t;
|
||||
import lwjake2.render.model_t;
|
||||
|
||||
public class clientinfo_t {
|
||||
String name ="";
|
||||
String cinfo ="";
|
||||
image_t skin; // ptr
|
||||
image_t icon; // ptr
|
||||
String iconname ="";
|
||||
model_t model; // ptr
|
||||
model_t weaponmodel[] = new model_t[Defines.MAX_CLIENTWEAPONMODELS]; // arary of references
|
||||
|
||||
// public void reset()
|
||||
// {
|
||||
// set(new clientinfo_t());
|
||||
// }
|
||||
|
||||
public void set (clientinfo_t from)
|
||||
{
|
||||
name = from.name;
|
||||
cinfo = from.cinfo;
|
||||
skin = from.skin;
|
||||
icon = from.icon;
|
||||
iconname = from.iconname;
|
||||
model = from.model;
|
||||
System.arraycopy(from.weaponmodel,0, weaponmodel, 0 , Defines.MAX_CLIENTWEAPONMODELS);
|
||||
}
|
||||
}
|
||||
44
src/main/java/lwjake2/client/console_t.java
Normal file
44
src/main/java/lwjake2/client/console_t.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.Defines;
|
||||
|
||||
/**
|
||||
* console_t
|
||||
*/
|
||||
public final class console_t {
|
||||
boolean initialized;
|
||||
byte[] text = new byte[Defines.CON_TEXTSIZE];
|
||||
int current; // line where next message will be printed
|
||||
int x; // offset in current line for next print
|
||||
int display; // bottom of console displays this line
|
||||
|
||||
int ormask; // high bit mask for colored characters
|
||||
|
||||
int linewidth; // characters across screen
|
||||
int totallines; // total lines in console scrollback
|
||||
|
||||
float cursorspeed;
|
||||
|
||||
int vislines;
|
||||
|
||||
float[] times = new float[Defines.NUM_CON_TIMES]; // cls.realtime time the line was generated
|
||||
// for transparent notify lines
|
||||
}
|
||||
39
src/main/java/lwjake2/client/cparticle_t.java
Normal file
39
src/main/java/lwjake2/client/cparticle_t.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
/**
|
||||
* cparticle_t
|
||||
*
|
||||
* @author cwei
|
||||
*/
|
||||
public class cparticle_t {
|
||||
|
||||
public cparticle_t next;
|
||||
public float time;
|
||||
|
||||
public float[] org = {0, 0, 0}; // vec3_t
|
||||
public float[] vel = {0, 0, 0}; // vec3_t
|
||||
public float[] accel = {0, 0, 0}; // vec3_t
|
||||
|
||||
public float color;
|
||||
//public float colorvel;
|
||||
public float alpha;
|
||||
public float alphavel;
|
||||
}
|
||||
26
src/main/java/lwjake2/client/dlight_t.java
Normal file
26
src/main/java/lwjake2/client/dlight_t.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
public class dlight_t
|
||||
{
|
||||
public float origin[] = { 0, 0, 0 };
|
||||
public float color[] = { 0, 0, 0 };
|
||||
public float intensity;
|
||||
}
|
||||
86
src/main/java/lwjake2/client/entity_t.java
Normal file
86
src/main/java/lwjake2/client/entity_t.java
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.render.image_t;
|
||||
import lwjake2.render.model_t;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
public class entity_t implements Cloneable{
|
||||
//ptr
|
||||
public model_t model; // opaque type outside refresh
|
||||
public float angles[] = { 0, 0, 0 };
|
||||
|
||||
/*
|
||||
** most recent data
|
||||
*/
|
||||
public float origin[] = { 0, 0, 0 }; // also used as RF_BEAM's "from"
|
||||
public int frame; // also used as RF_BEAM's diameter
|
||||
|
||||
/*
|
||||
** previous data for lerping
|
||||
*/
|
||||
public float oldorigin[] = { 0, 0, 0 }; // also used as RF_BEAM's "to"
|
||||
public int oldframe;
|
||||
|
||||
/*
|
||||
** misc
|
||||
*/
|
||||
public float backlerp; // 0.0 = current, 1.0 = old
|
||||
public int skinnum; // also used as RF_BEAM's palette index
|
||||
|
||||
public int lightstyle; // for flashing entities
|
||||
public float alpha; // ignore if RF_TRANSLUCENT isn't set
|
||||
|
||||
// reference
|
||||
public image_t skin; // NULL for inline skin
|
||||
public int flags;
|
||||
|
||||
|
||||
public void set(entity_t src) {
|
||||
this.model = src.model;
|
||||
Math3D.VectorCopy(src.angles, this.angles);
|
||||
Math3D.VectorCopy(src.origin, this.origin);
|
||||
this.frame = src.frame;
|
||||
Math3D.VectorCopy(src.oldorigin, this.oldorigin);
|
||||
this.oldframe = src.oldframe;
|
||||
this.backlerp = src.backlerp;
|
||||
this.skinnum = src.skinnum;
|
||||
this.lightstyle = src.lightstyle;
|
||||
this.alpha = src.alpha;
|
||||
this.skin = src.skin;
|
||||
this.flags = src.flags;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
model = null;
|
||||
Math3D.VectorClear(angles);
|
||||
Math3D.VectorClear(origin);
|
||||
frame = 0;
|
||||
Math3D.VectorClear(oldorigin);
|
||||
oldframe = 0;
|
||||
backlerp = 0;
|
||||
skinnum = 0;
|
||||
lightstyle = 0;
|
||||
alpha = 0;
|
||||
skin = null;
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
}
|
||||
56
src/main/java/lwjake2/client/frame_t.java
Normal file
56
src/main/java/lwjake2/client/frame_t.java
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.game.player_state_t;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class frame_t {
|
||||
|
||||
public static final int MAX_MAP_AREAS = 256;
|
||||
|
||||
boolean valid; // cleared if delta parsing was invalid
|
||||
int serverframe;
|
||||
public int servertime; // server time the message is valid for (in msec)
|
||||
int deltaframe;
|
||||
byte areabits[] = new byte [MAX_MAP_AREAS/8]; // portalarea visibility bits
|
||||
public player_state_t playerstate = new player_state_t(); // mem
|
||||
public int num_entities;
|
||||
public int parse_entities; // non-masked index into cl_parse_entities array
|
||||
|
||||
public void set(frame_t from) {
|
||||
valid = from.valid;
|
||||
serverframe = from.serverframe;
|
||||
deltaframe = from.deltaframe;
|
||||
num_entities = from.num_entities;
|
||||
parse_entities = from.parse_entities;
|
||||
System.arraycopy(from.areabits, 0, areabits, 0, areabits.length);
|
||||
playerstate.set(from.playerstate);
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
valid = false;
|
||||
serverframe = servertime = deltaframe = 0;
|
||||
Arrays.fill(areabits, (byte)0);
|
||||
playerstate.clear();
|
||||
num_entities = parse_entities = 0;
|
||||
}
|
||||
}
|
||||
29
src/main/java/lwjake2/client/kbutton_t.java
Normal file
29
src/main/java/lwjake2/client/kbutton_t.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
/**
|
||||
* kbutton_t
|
||||
*/
|
||||
public class kbutton_t {
|
||||
int[] down = new int[2]; // key nums holding it down
|
||||
long downtime; // msec timestamp
|
||||
long msec; // msec down this frame
|
||||
public int state;
|
||||
}
|
||||
25
src/main/java/lwjake2/client/lightstyle_t.java
Normal file
25
src/main/java/lwjake2/client/lightstyle_t.java
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
public class lightstyle_t
|
||||
{
|
||||
public float rgb[] = { 0, 0, 0 }; // 0.0 - 2.0
|
||||
public float white; // highest of rgb
|
||||
}
|
||||
48
src/main/java/lwjake2/client/particle_t.java
Normal file
48
src/main/java/lwjake2/client/particle_t.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.util.Lib;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
public class particle_t {
|
||||
|
||||
// lwjgl renderer needs a ByteBuffer
|
||||
private static ByteBuffer colorByteArray = Lib.newByteBuffer(Defines.MAX_PARTICLES * Lib.SIZEOF_INT, ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
public static FloatBuffer vertexArray = Lib.newFloatBuffer(Defines.MAX_PARTICLES * 3);
|
||||
public static int[] colorTable = new int[256];
|
||||
public static IntBuffer colorArray = colorByteArray.asIntBuffer();
|
||||
|
||||
|
||||
public static void setColorPalette(int[] palette) {
|
||||
for (int i=0; i < 256; i++) {
|
||||
colorTable[i] = palette[i] & 0x00FFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
public static ByteBuffer getColorAsByteBuffer() {
|
||||
return colorByteArray;
|
||||
}
|
||||
}
|
||||
42
src/main/java/lwjake2/client/refdef_t.java
Normal file
42
src/main/java/lwjake2/client/refdef_t.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
public class refdef_t {
|
||||
public int x, y, width, height;// in virtual screen coordinates
|
||||
public float fov_x, fov_y;
|
||||
public float vieworg[] ={0,0,0};
|
||||
public float viewangles[]={0,0,0};
|
||||
public float blend[]={0,0,0,0}; // rgba 0-1 full screen blend
|
||||
public float time; // time is uesed to auto animate
|
||||
public int rdflags; // RDF_UNDERWATER, etc
|
||||
|
||||
public byte areabits[]; // if not NULL, only areas with set bits will be drawn
|
||||
|
||||
public lightstyle_t lightstyles[]; // [MAX_LIGHTSTYLES]
|
||||
|
||||
public int num_entities;
|
||||
public entity_t entities[];
|
||||
|
||||
public int num_dlights;
|
||||
public dlight_t dlights[];
|
||||
|
||||
public int num_particles;
|
||||
//public particle_t particles[];
|
||||
}
|
||||
104
src/main/java/lwjake2/client/refexport_t.java
Normal file
104
src/main/java/lwjake2/client/refexport_t.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import lwjake2.render.image_t;
|
||||
import lwjake2.render.model_t;
|
||||
import lwjake2.sys.KBD;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.DisplayMode;
|
||||
|
||||
/**
|
||||
* refexport_t
|
||||
*
|
||||
* @author cwei
|
||||
*/
|
||||
public interface refexport_t {
|
||||
// ============================================================================
|
||||
// public interface for Renderer implementations
|
||||
//
|
||||
// ref.h, refexport_t
|
||||
// ============================================================================
|
||||
//
|
||||
// these are the functions exported by the refresh module
|
||||
//
|
||||
// called when the library is loaded
|
||||
boolean Init(int vid_xpos, int vid_ypos);
|
||||
|
||||
// called before the library is unloaded
|
||||
void Shutdown();
|
||||
|
||||
// All data that will be used in a level should be
|
||||
// registered before rendering any frames to prevent disk hits,
|
||||
// but they can still be registered at a later time
|
||||
// if necessary.
|
||||
//
|
||||
// EndRegistration will free any remaining data that wasn't registered.
|
||||
// Any model_s or skin_s pointers from before the BeginRegistration
|
||||
// are no longer valid after EndRegistration.
|
||||
//
|
||||
// Skins and images need to be differentiated, because skins
|
||||
// are flood filled to eliminate mip map edge errors, and pics have
|
||||
// an implicit "pics/" prepended to the name. (a pic name that starts with a
|
||||
// slash will not use the "pics/" prefix or the ".pcx" postfix)
|
||||
void BeginRegistration(String map);
|
||||
model_t RegisterModel(String name);
|
||||
image_t RegisterSkin(String name);
|
||||
image_t RegisterPic(String name);
|
||||
void SetSky(String name, float rotate, /* vec3_t */
|
||||
float[] axis);
|
||||
void EndRegistration();
|
||||
|
||||
void RenderFrame(refdef_t fd);
|
||||
|
||||
void DrawGetPicSize(Dimension dim /* int *w, *h */, String name);
|
||||
// will return 0 0 if not found
|
||||
void DrawPic(int x, int y, String name);
|
||||
void DrawStretchPic(int x, int y, int w, int h, String name);
|
||||
void DrawChar(int x, int y, int num); // num is 8 bit ASCII
|
||||
void DrawTileClear(int x, int y, int w, int h, String name);
|
||||
void DrawFill(int x, int y, int w, int h, int c);
|
||||
void DrawFadeScreen();
|
||||
|
||||
// Draw images for cinematic rendering (which can have a different palette). Note that calls
|
||||
void DrawStretchRaw(int x, int y, int w, int h, int cols, int rows, byte[] data);
|
||||
|
||||
/*
|
||||
** video mode and refresh state management entry points
|
||||
*/
|
||||
/* 256 r,g,b values; null = game palette, size = 768 bytes */
|
||||
void CinematicSetPalette(final byte[] palette);
|
||||
void BeginFrame(float camera_separation);
|
||||
void EndFrame();
|
||||
|
||||
void AppActivate(boolean activate);
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
void updateScreen(Runnable callback);
|
||||
|
||||
int apiVersion();
|
||||
|
||||
DisplayMode[] getModeList();
|
||||
|
||||
KBD getKeyboardHandler();
|
||||
}
|
||||
23
src/main/java/lwjake2/client/viddef_t.java
Normal file
23
src/main/java/lwjake2/client/viddef_t.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
public class viddef_t {
|
||||
public int width, height;
|
||||
}
|
||||
37
src/main/java/lwjake2/client/vidmode_t.java
Normal file
37
src/main/java/lwjake2/client/vidmode_t.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
/**
|
||||
* vidmode_t
|
||||
*
|
||||
* @author cwei
|
||||
*/
|
||||
public class vidmode_t {
|
||||
String description;
|
||||
int width, height;
|
||||
int mode;
|
||||
|
||||
vidmode_t (String description, int width, int height, int mode) {
|
||||
this.description = description;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.mode = mode;
|
||||
}
|
||||
}
|
||||
32
src/main/java/lwjake2/client/vrect_t.java
Normal file
32
src/main/java/lwjake2/client/vrect_t.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
/**
|
||||
* vrect_t
|
||||
*
|
||||
* @author cwei
|
||||
*/
|
||||
public class vrect_t {
|
||||
public int x;
|
||||
public int y;
|
||||
public int width;
|
||||
public int height;
|
||||
vrect_t pnext;
|
||||
}
|
||||
24
src/main/java/lwjake2/game/AIAdapter.java
Normal file
24
src/main/java/lwjake2/game/AIAdapter.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public abstract class AIAdapter extends SuperAdapter
|
||||
{
|
||||
public abstract void ai(edict_t self, float dist);
|
||||
}
|
||||
1267
src/main/java/lwjake2/game/Cmd.java
Normal file
1267
src/main/java/lwjake2/game/Cmd.java
Normal file
File diff suppressed because it is too large
Load Diff
29
src/main/java/lwjake2/game/EdictFindFilter.java
Normal file
29
src/main/java/lwjake2/game/EdictFindFilter.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
/** Helps for filtering the iteration over the gedicts[] array, see GFind(). RST. */
|
||||
|
||||
public class EdictFindFilter
|
||||
{
|
||||
boolean matches(edict_t e, String s)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
}
|
||||
31
src/main/java/lwjake2/game/EdictIterator.java
Normal file
31
src/main/java/lwjake2/game/EdictIterator.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
/** Helps for iterating over the gedicts[] array. RST. */
|
||||
|
||||
public class EdictIterator
|
||||
{
|
||||
EdictIterator(int i)
|
||||
{
|
||||
this.i = i;
|
||||
}
|
||||
public edict_t o;
|
||||
int i;
|
||||
}
|
||||
69
src/main/java/lwjake2/game/EndianHandler.java
Normal file
69
src/main/java/lwjake2/game/EndianHandler.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public abstract class EndianHandler
|
||||
{
|
||||
private static final int mask = 0xFF;
|
||||
|
||||
abstract public float BigFloat(float f);
|
||||
abstract public short BigShort(short s);
|
||||
abstract public int BigLong(int i);
|
||||
abstract public float LittleFloat(float f);
|
||||
abstract public short LittleShort(short s);
|
||||
abstract public int LittleLong(int i);
|
||||
|
||||
public static float swapFloat(float f)
|
||||
{
|
||||
int i = Float.floatToRawIntBits(f);
|
||||
i = swapInt(i);
|
||||
f = Float.intBitsToFloat(i);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
public static int swapInt(int i)
|
||||
{
|
||||
|
||||
int a = i & mask;
|
||||
i >>>= 8;
|
||||
|
||||
a <<= 24;
|
||||
|
||||
int b = i & mask;
|
||||
|
||||
i >>>= 8;
|
||||
b <<= 16;
|
||||
|
||||
int c = i & mask;
|
||||
i >>>= 8;
|
||||
c <<= 8;
|
||||
|
||||
return i | c | b | a;
|
||||
}
|
||||
|
||||
public static short swapShort(short s)
|
||||
{
|
||||
int a = s & mask;
|
||||
a <<= 8;
|
||||
int b = (s >>> 8) & mask;
|
||||
|
||||
return (short) (b | a);
|
||||
}
|
||||
}
|
||||
25
src/main/java/lwjake2/game/EntBlockedAdapter.java
Normal file
25
src/main/java/lwjake2/game/EntBlockedAdapter.java
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public abstract class EntBlockedAdapter extends SuperAdapter
|
||||
{
|
||||
// move to moveinfo?
|
||||
public abstract void blocked(edict_t self, edict_t other);
|
||||
}
|
||||
24
src/main/java/lwjake2/game/EntDieAdapter.java
Normal file
24
src/main/java/lwjake2/game/EntDieAdapter.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public abstract class EntDieAdapter extends SuperAdapter
|
||||
{
|
||||
public abstract void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point);
|
||||
}
|
||||
24
src/main/java/lwjake2/game/EntDodgeAdapter.java
Normal file
24
src/main/java/lwjake2/game/EntDodgeAdapter.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public abstract class EntDodgeAdapter extends SuperAdapter
|
||||
{
|
||||
public abstract void dodge(edict_t self, edict_t other, float eta);
|
||||
}
|
||||
24
src/main/java/lwjake2/game/EntInteractAdapter.java
Normal file
24
src/main/java/lwjake2/game/EntInteractAdapter.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public abstract class EntInteractAdapter extends SuperAdapter
|
||||
{
|
||||
public abstract boolean interact(edict_t self, edict_t other);
|
||||
}
|
||||
24
src/main/java/lwjake2/game/EntPainAdapter.java
Normal file
24
src/main/java/lwjake2/game/EntPainAdapter.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public abstract class EntPainAdapter extends SuperAdapter
|
||||
{
|
||||
public abstract void pain(edict_t self, edict_t other, float kick, int damage);
|
||||
}
|
||||
24
src/main/java/lwjake2/game/EntThinkAdapter.java
Normal file
24
src/main/java/lwjake2/game/EntThinkAdapter.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public abstract class EntThinkAdapter extends SuperAdapter
|
||||
{
|
||||
public abstract boolean think(edict_t self);
|
||||
}
|
||||
24
src/main/java/lwjake2/game/EntTouchAdapter.java
Normal file
24
src/main/java/lwjake2/game/EntTouchAdapter.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public abstract class EntTouchAdapter extends SuperAdapter
|
||||
{
|
||||
public abstract void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf);
|
||||
}
|
||||
24
src/main/java/lwjake2/game/EntUseAdapter.java
Normal file
24
src/main/java/lwjake2/game/EntUseAdapter.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public abstract class EntUseAdapter extends SuperAdapter
|
||||
{
|
||||
public abstract void use(edict_t self, edict_t other, edict_t activator);
|
||||
}
|
||||
758
src/main/java/lwjake2/game/GameAI.java
Normal file
758
src/main/java/lwjake2/game/GameAI.java
Normal file
@@ -0,0 +1,758 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.client.M;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
|
||||
public class GameAI {
|
||||
|
||||
public static void AttackFinished(edict_t self, float time) {
|
||||
self.monsterinfo.attack_finished = GameBase.level.time + time;
|
||||
}
|
||||
|
||||
/** Don't move, but turn towards ideal_yaw Distance is for slight position
|
||||
* adjustments needed by the animations.
|
||||
*/
|
||||
public static void ai_turn(edict_t self, float dist) {
|
||||
if (dist != 0)
|
||||
M.M_walkmove(self, self.s.angles[Defines.YAW], dist);
|
||||
|
||||
if (GameUtil.FindTarget(self))
|
||||
return;
|
||||
|
||||
M.M_ChangeYaw(self);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks, if the monster should turn left/right.
|
||||
*/
|
||||
|
||||
public static boolean FacingIdeal(edict_t self) {
|
||||
float delta;
|
||||
|
||||
delta = Math3D.anglemod(self.s.angles[Defines.YAW] - self.ideal_yaw);
|
||||
if (delta > 45 && delta < 315)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn and close until within an angle to launch a melee attack.
|
||||
*/
|
||||
public static void ai_run_melee(edict_t self) {
|
||||
self.ideal_yaw = enemy_yaw;
|
||||
M.M_ChangeYaw(self);
|
||||
|
||||
if (FacingIdeal(self)) {
|
||||
self.monsterinfo.melee.think(self);
|
||||
self.monsterinfo.attack_state = Defines.AS_STRAIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn in place until within an angle to launch a missile attack.
|
||||
*/
|
||||
public static void ai_run_missile(edict_t self) {
|
||||
self.ideal_yaw = enemy_yaw;
|
||||
M.M_ChangeYaw(self);
|
||||
|
||||
if (FacingIdeal(self)) {
|
||||
self.monsterinfo.attack.think(self);
|
||||
self.monsterinfo.attack_state = Defines.AS_STRAIGHT;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Strafe sideways, but stay at aproximately the same range.
|
||||
*/
|
||||
public static void ai_run_slide(edict_t self, float distance) {
|
||||
float ofs;
|
||||
|
||||
self.ideal_yaw = enemy_yaw;
|
||||
M.M_ChangeYaw(self);
|
||||
|
||||
if (self.monsterinfo.lefty != 0)
|
||||
ofs = 90;
|
||||
else
|
||||
ofs = -90;
|
||||
|
||||
if (M.M_walkmove(self, self.ideal_yaw + ofs, distance))
|
||||
return;
|
||||
|
||||
self.monsterinfo.lefty = 1 - self.monsterinfo.lefty;
|
||||
M.M_walkmove(self, self.ideal_yaw - ofs, distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides if we're going to attack or do something else used by ai_run and
|
||||
* ai_stand.
|
||||
*
|
||||
* .enemy Will be world if not currently angry at anyone.
|
||||
*
|
||||
* .movetarget The next path spot to walk toward. If .enemy, ignore
|
||||
* .movetarget. When an enemy is killed, the monster will try to return to
|
||||
* it's path.
|
||||
*
|
||||
* .hunt_time Set to time + something when the player is in sight, but
|
||||
* movement straight for him is blocked. This causes the monster to use wall
|
||||
* following code for movement direction instead of sighting on the player.
|
||||
*
|
||||
* .ideal_yaw A yaw angle of the intended direction, which will be turned
|
||||
* towards at up to 45 deg / state. If the enemy is in view and hunt_time is
|
||||
* not active, this will be the exact line towards the enemy.
|
||||
*
|
||||
* .pausetime A monster will leave it's stand state and head towards it's
|
||||
* .movetarget when time > .pausetime.
|
||||
*
|
||||
* walkmove(angle, speed) primitive is all or nothing
|
||||
*/
|
||||
public static boolean ai_checkattack(edict_t self, float dist) {
|
||||
float temp[] = { 0, 0, 0 };
|
||||
|
||||
boolean hesDeadJim;
|
||||
|
||||
// this causes monsters to run blindly to the combat point w/o firing
|
||||
if (self.goalentity != null) {
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_COMBAT_POINT) != 0)
|
||||
return false;
|
||||
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_SOUND_TARGET) != 0) {
|
||||
if ((GameBase.level.time - self.enemy.teleport_time) > 5.0) {
|
||||
if (self.goalentity == self.enemy)
|
||||
if (self.movetarget != null)
|
||||
self.goalentity = self.movetarget;
|
||||
else
|
||||
self.goalentity = null;
|
||||
self.monsterinfo.aiflags &= ~Defines.AI_SOUND_TARGET;
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_TEMP_STAND_GROUND) != 0)
|
||||
self.monsterinfo.aiflags &= ~(Defines.AI_STAND_GROUND | Defines.AI_TEMP_STAND_GROUND);
|
||||
} else {
|
||||
self.show_hostile = (int) GameBase.level.time + 1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enemy_vis = false;
|
||||
|
||||
// see if the enemy is dead
|
||||
hesDeadJim = false;
|
||||
if ((null == self.enemy) || (!self.enemy.inuse)) {
|
||||
hesDeadJim = true;
|
||||
} else if ((self.monsterinfo.aiflags & Defines.AI_MEDIC) != 0) {
|
||||
if (self.enemy.health > 0) {
|
||||
hesDeadJim = true;
|
||||
self.monsterinfo.aiflags &= ~Defines.AI_MEDIC;
|
||||
}
|
||||
} else {
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_BRUTAL) != 0) {
|
||||
if (self.enemy.health <= -80)
|
||||
hesDeadJim = true;
|
||||
} else {
|
||||
if (self.enemy.health <= 0)
|
||||
hesDeadJim = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hesDeadJim) {
|
||||
self.enemy = null;
|
||||
// FIXME: look all around for other targets
|
||||
if (self.oldenemy != null && self.oldenemy.health > 0) {
|
||||
self.enemy = self.oldenemy;
|
||||
self.oldenemy = null;
|
||||
HuntTarget(self);
|
||||
} else {
|
||||
if (self.movetarget != null) {
|
||||
self.goalentity = self.movetarget;
|
||||
self.monsterinfo.walk.think(self);
|
||||
} else {
|
||||
// we need the pausetime otherwise the stand code
|
||||
// will just revert to walking with no target and
|
||||
// the monsters will wonder around aimlessly trying
|
||||
// to hunt the world entity
|
||||
self.monsterinfo.pausetime = GameBase.level.time + 100000000;
|
||||
self.monsterinfo.stand.think(self);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
self.show_hostile = (int) GameBase.level.time + 1; // wake up other
|
||||
|
||||
// monsters check knowledge of enemy
|
||||
enemy_vis = GameUtil.visible(self, self.enemy);
|
||||
if (enemy_vis) {
|
||||
self.monsterinfo.search_time = GameBase.level.time + 5;
|
||||
Math3D.VectorCopy(self.enemy.s.origin,
|
||||
self.monsterinfo.last_sighting);
|
||||
}
|
||||
|
||||
enemy_infront = GameUtil.infront(self, self.enemy);
|
||||
enemy_range = GameUtil.range(self, self.enemy);
|
||||
Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, temp);
|
||||
enemy_yaw = Math3D.vectoyaw(temp);
|
||||
|
||||
// JDC self.ideal_yaw = enemy_yaw;
|
||||
|
||||
if (self.monsterinfo.attack_state == Defines.AS_MISSILE) {
|
||||
ai_run_missile(self);
|
||||
return true;
|
||||
}
|
||||
if (self.monsterinfo.attack_state == Defines.AS_MELEE) {
|
||||
ai_run_melee(self);
|
||||
return true;
|
||||
}
|
||||
|
||||
// if enemy is not currently visible, we will never attack
|
||||
if (!enemy_vis)
|
||||
return false;
|
||||
|
||||
return self.monsterinfo.checkattack.think(self);
|
||||
}
|
||||
|
||||
/**
|
||||
* The monster is walking it's beat.
|
||||
*/
|
||||
static void ai_walk(edict_t self, float dist) {
|
||||
M.M_MoveToGoal(self, dist);
|
||||
|
||||
// check for noticing a player
|
||||
if (GameUtil.FindTarget(self))
|
||||
return;
|
||||
|
||||
if ((self.monsterinfo.search != null)
|
||||
&& (GameBase.level.time > self.monsterinfo.idle_time)) {
|
||||
if (self.monsterinfo.idle_time != 0) {
|
||||
self.monsterinfo.search.think(self);
|
||||
self.monsterinfo.idle_time = GameBase.level.time + 15
|
||||
+ Lib.random() * 15;
|
||||
} else {
|
||||
self.monsterinfo.idle_time = GameBase.level.time + Lib.random()
|
||||
* 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called once each frame to set level.sight_client to the player to be
|
||||
* checked for in findtarget.
|
||||
*
|
||||
* If all clients are either dead or in notarget, sight_client will be null.
|
||||
*
|
||||
* In coop games, sight_client will cycle between the clients.
|
||||
*/
|
||||
static void AI_SetSightClient() {
|
||||
edict_t ent;
|
||||
int start, check;
|
||||
|
||||
if (GameBase.level.sight_client == null)
|
||||
start = 1;
|
||||
else
|
||||
start = GameBase.level.sight_client.index;
|
||||
|
||||
check = start;
|
||||
while (true) {
|
||||
check++;
|
||||
if (check > GameBase.game.maxclients)
|
||||
check = 1;
|
||||
ent = GameBase.g_edicts[check];
|
||||
|
||||
if (ent.inuse && ent.health > 0
|
||||
&& (ent.flags & Defines.FL_NOTARGET) == 0) {
|
||||
GameBase.level.sight_client = ent;
|
||||
return; // got one
|
||||
}
|
||||
if (check == start) {
|
||||
GameBase.level.sight_client = null;
|
||||
return; // nobody to see
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the specified distance at current facing. This replaces the QC
|
||||
* functions: ai_forward, ai_back, ai_pain, and ai_painforward
|
||||
*/
|
||||
static void ai_move(edict_t self, float dist) {
|
||||
M.M_walkmove(self, self.s.angles[Defines.YAW], dist);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decides running or standing according to flag AI_STAND_GROUND.
|
||||
*/
|
||||
static void HuntTarget(edict_t self) {
|
||||
float[] vec = { 0, 0, 0 };
|
||||
|
||||
self.goalentity = self.enemy;
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_STAND_GROUND) != 0)
|
||||
self.monsterinfo.stand.think(self);
|
||||
else
|
||||
self.monsterinfo.run.think(self);
|
||||
Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, vec);
|
||||
self.ideal_yaw = Math3D.vectoyaw(vec);
|
||||
|
||||
// wait a while before first attack
|
||||
if (0 == (self.monsterinfo.aiflags & Defines.AI_STAND_GROUND))
|
||||
GameUtil.AttackFinished(self, 1);
|
||||
}
|
||||
|
||||
|
||||
public static EntThinkAdapter walkmonster_start_go = new EntThinkAdapter() {
|
||||
public String getID() { return "walkmonster_start_go"; }
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
if (0 == (self.spawnflags & 2) && GameBase.level.time < 1) {
|
||||
M.M_droptofloor.think(self);
|
||||
|
||||
if (self.groundentity != null)
|
||||
if (!M.M_walkmove(self, 0, 0))
|
||||
GameBase.gi.dprintf(self.classname + " in solid at "
|
||||
+ Lib.vtos(self.s.origin) + "\n");
|
||||
}
|
||||
|
||||
if (0 == self.yaw_speed)
|
||||
self.yaw_speed = 40;
|
||||
self.viewheight = 25;
|
||||
|
||||
Monster.monster_start_go(self);
|
||||
|
||||
if ((self.spawnflags & 2) != 0)
|
||||
Monster.monster_triggered_start.think(self);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static EntThinkAdapter walkmonster_start = new EntThinkAdapter() {
|
||||
public String getID() { return "walkmonster_start";}
|
||||
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
self.think = walkmonster_start_go;
|
||||
Monster.monster_start(self);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static EntThinkAdapter flymonster_start_go = new EntThinkAdapter() {
|
||||
public String getID() { return "flymonster_start_go";}
|
||||
public boolean think(edict_t self) {
|
||||
if (!M.M_walkmove(self, 0, 0))
|
||||
GameBase.gi.dprintf(self.classname + " in solid at "
|
||||
+ Lib.vtos(self.s.origin) + "\n");
|
||||
|
||||
if (0 == self.yaw_speed)
|
||||
self.yaw_speed = 20;
|
||||
self.viewheight = 25;
|
||||
|
||||
Monster.monster_start_go(self);
|
||||
|
||||
if ((self.spawnflags & 2) != 0)
|
||||
Monster.monster_triggered_start.think(self);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static EntThinkAdapter flymonster_start = new EntThinkAdapter() {
|
||||
public String getID() { return "flymonster_start";}
|
||||
public boolean think(edict_t self) {
|
||||
self.flags |= Defines.FL_FLY;
|
||||
self.think = flymonster_start_go;
|
||||
Monster.monster_start(self);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static EntThinkAdapter swimmonster_start_go = new EntThinkAdapter() {
|
||||
public String getID() { return "swimmonster_start_go";}
|
||||
public boolean think(edict_t self) {
|
||||
if (0 == self.yaw_speed)
|
||||
self.yaw_speed = 20;
|
||||
self.viewheight = 10;
|
||||
|
||||
Monster.monster_start_go(self);
|
||||
|
||||
if ((self.spawnflags & 2) != 0)
|
||||
Monster.monster_triggered_start.think(self);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static EntThinkAdapter swimmonster_start = new EntThinkAdapter() {
|
||||
public String getID() { return "swimmonster_start";}
|
||||
public boolean think(edict_t self) {
|
||||
self.flags |= Defines.FL_SWIM;
|
||||
self.think = swimmonster_start_go;
|
||||
Monster.monster_start(self);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Don't move, but turn towards ideal_yaw Distance is for slight position
|
||||
* adjustments needed by the animations
|
||||
*/
|
||||
public static AIAdapter ai_turn = new AIAdapter() {
|
||||
public String getID() { return "ai_turn";}
|
||||
public void ai(edict_t self, float dist) {
|
||||
|
||||
if (dist != 0)
|
||||
M.M_walkmove(self, self.s.angles[Defines.YAW], dist);
|
||||
|
||||
if (GameUtil.FindTarget(self))
|
||||
return;
|
||||
|
||||
M.M_ChangeYaw(self);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Move the specified distance at current facing. This replaces the QC
|
||||
* functions: ai_forward, ai_back, ai_pain, and ai_painforward
|
||||
*/
|
||||
public static AIAdapter ai_move = new AIAdapter() {
|
||||
public String getID() { return "ai_move";}
|
||||
public void ai(edict_t self, float dist) {
|
||||
M.M_walkmove(self, self.s.angles[Defines.YAW], dist);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The monster is walking it's beat.
|
||||
*/
|
||||
public static AIAdapter ai_walk = new AIAdapter() {
|
||||
public String getID() { return "ai_walk";}
|
||||
public void ai(edict_t self, float dist) {
|
||||
M.M_MoveToGoal(self, dist);
|
||||
|
||||
// check for noticing a player
|
||||
if (GameUtil.FindTarget(self))
|
||||
return;
|
||||
|
||||
if ((self.monsterinfo.search != null)
|
||||
&& (GameBase.level.time > self.monsterinfo.idle_time)) {
|
||||
if (self.monsterinfo.idle_time != 0) {
|
||||
self.monsterinfo.search.think(self);
|
||||
self.monsterinfo.idle_time = GameBase.level.time + 15 + Globals.rnd.nextFloat() * 15;
|
||||
} else {
|
||||
self.monsterinfo.idle_time = GameBase.level.time + Globals.rnd.nextFloat() * 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Used for standing around and looking for players Distance is for slight
|
||||
* position adjustments needed by the animations.
|
||||
*/
|
||||
|
||||
public static AIAdapter ai_stand = new AIAdapter() {
|
||||
public String getID() { return "ai_stand";}
|
||||
public void ai(edict_t self, float dist) {
|
||||
float[] v = { 0, 0, 0 };
|
||||
|
||||
if (dist != 0)
|
||||
M.M_walkmove(self, self.s.angles[Defines.YAW], dist);
|
||||
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_STAND_GROUND) != 0) {
|
||||
if (self.enemy != null) {
|
||||
Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, v);
|
||||
self.ideal_yaw = Math3D.vectoyaw(v);
|
||||
if (self.s.angles[Defines.YAW] != self.ideal_yaw
|
||||
&& 0 != (self.monsterinfo.aiflags & Defines.AI_TEMP_STAND_GROUND)) {
|
||||
self.monsterinfo.aiflags &= ~(Defines.AI_STAND_GROUND | Defines.AI_TEMP_STAND_GROUND);
|
||||
self.monsterinfo.run.think(self);
|
||||
}
|
||||
M.M_ChangeYaw(self);
|
||||
ai_checkattack(self, 0);
|
||||
} else
|
||||
GameUtil.FindTarget(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameUtil.FindTarget(self))
|
||||
return;
|
||||
|
||||
if (GameBase.level.time > self.monsterinfo.pausetime) {
|
||||
self.monsterinfo.walk.think(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 == (self.spawnflags & 1) && (self.monsterinfo.idle != null)
|
||||
&& (GameBase.level.time > self.monsterinfo.idle_time)) {
|
||||
if (self.monsterinfo.idle_time != 0) {
|
||||
self.monsterinfo.idle.think(self);
|
||||
self.monsterinfo.idle_time = GameBase.level.time + 15 + Globals.rnd.nextFloat() * 15;
|
||||
} else {
|
||||
self.monsterinfo.idle_time = GameBase.level.time + Globals.rnd.nextFloat() * 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Turns towards target and advances Use this call with a distnace of 0 to
|
||||
* replace ai_face.
|
||||
*/
|
||||
public static AIAdapter ai_charge = new AIAdapter() {
|
||||
public String getID() { return "ai_charge";}
|
||||
public void ai(edict_t self, float dist) {
|
||||
float[] v = { 0, 0, 0 };
|
||||
|
||||
Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, v);
|
||||
self.ideal_yaw = Math3D.vectoyaw(v);
|
||||
M.M_ChangeYaw(self);
|
||||
|
||||
if (dist != 0)
|
||||
M.M_walkmove(self, self.s.angles[Defines.YAW], dist);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The monster has an enemy it is trying to kill.
|
||||
*/
|
||||
public static AIAdapter ai_run = new AIAdapter() {
|
||||
public String getID() { return "ai_run";}
|
||||
public void ai(edict_t self, float dist) {
|
||||
float[] v = { 0, 0, 0 };
|
||||
|
||||
edict_t tempgoal;
|
||||
edict_t save;
|
||||
boolean new1;
|
||||
edict_t marker;
|
||||
float d1, d2;
|
||||
trace_t tr; // mem
|
||||
float[] v_forward = { 0, 0, 0 }, v_right = { 0, 0, 0 };
|
||||
float left, center, right;
|
||||
float[] left_target = { 0, 0, 0 }, right_target = { 0, 0, 0 };
|
||||
|
||||
// if we're going to a combat point, just proceed
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_COMBAT_POINT) != 0) {
|
||||
M.M_MoveToGoal(self, dist);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_SOUND_TARGET) != 0) {
|
||||
Math3D.VectorSubtract(self.s.origin, self.enemy.s.origin, v);
|
||||
// ...and reached it
|
||||
if (Math3D.VectorLength(v) < 64) {
|
||||
//don't move, just stand and listen.
|
||||
//self.monsterinfo.aiflags |= (Defines.AI_STAND_GROUND | Defines.AI_TEMP_STAND_GROUND);
|
||||
self.monsterinfo.stand.think(self);
|
||||
// since now it is aware and does not to be triggered again.
|
||||
self.spawnflags &= ~1;
|
||||
self.enemy = null;
|
||||
}
|
||||
else
|
||||
M.M_MoveToGoal(self, dist);
|
||||
|
||||
// look for new targets
|
||||
if (!GameUtil.FindTarget(self))
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (ai_checkattack(self, dist))
|
||||
return;
|
||||
|
||||
if (self.monsterinfo.attack_state == Defines.AS_SLIDING) {
|
||||
ai_run_slide(self, dist);
|
||||
return;
|
||||
}
|
||||
|
||||
if (enemy_vis) {
|
||||
//if (self.aiflags & AI_LOST_SIGHT)
|
||||
// dprint("regained sight\n");
|
||||
M.M_MoveToGoal(self, dist);
|
||||
self.monsterinfo.aiflags &= ~Defines.AI_LOST_SIGHT;
|
||||
Math3D.VectorCopy(self.enemy.s.origin, self.monsterinfo.last_sighting);
|
||||
self.monsterinfo.trail_time = GameBase.level.time;
|
||||
return;
|
||||
}
|
||||
|
||||
// coop will change to another enemy if visible
|
||||
if (GameBase.coop.value != 0) {
|
||||
// FIXME: insane guys get mad with this, which causes crashes!
|
||||
if (GameUtil.FindTarget(self))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ((self.monsterinfo.search_time != 0)
|
||||
&& (GameBase.level.time > (self.monsterinfo.search_time + 20))) {
|
||||
M.M_MoveToGoal(self, dist);
|
||||
self.monsterinfo.search_time = 0;
|
||||
//dprint("search timeout\n");
|
||||
return;
|
||||
}
|
||||
|
||||
save = self.goalentity;
|
||||
tempgoal = GameUtil.G_Spawn();
|
||||
self.goalentity = tempgoal;
|
||||
|
||||
new1 = false;
|
||||
|
||||
if (0 == (self.monsterinfo.aiflags & Defines.AI_LOST_SIGHT)) {
|
||||
// just lost sight of the player, decide where to go first
|
||||
// dprint("lost sight of player, last seen at ");
|
||||
// dprint(vtos(self.last_sighting));
|
||||
// dprint("\n");
|
||||
self.monsterinfo.aiflags |= (Defines.AI_LOST_SIGHT | Defines.AI_PURSUIT_LAST_SEEN);
|
||||
self.monsterinfo.aiflags &= ~(Defines.AI_PURSUE_NEXT | Defines.AI_PURSUE_TEMP);
|
||||
new1 = true;
|
||||
}
|
||||
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_PURSUE_NEXT) != 0) {
|
||||
self.monsterinfo.aiflags &= ~Defines.AI_PURSUE_NEXT;
|
||||
|
||||
// dprint("reached current goal: ");
|
||||
// dprint(vtos(self.origin));
|
||||
// dprint(" ");
|
||||
// dprint(vtos(self.last_sighting));
|
||||
// dprint(" ");
|
||||
// dprint(ftos(vlen(self.origin - self.last_sighting)));
|
||||
// dprint("\n");
|
||||
|
||||
// give ourself more time since we got this far
|
||||
self.monsterinfo.search_time = GameBase.level.time + 5;
|
||||
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_PURSUE_TEMP) != 0) {
|
||||
// dprint("was temp goal; retrying original\n");
|
||||
self.monsterinfo.aiflags &= ~Defines.AI_PURSUE_TEMP;
|
||||
marker = null;
|
||||
Math3D.VectorCopy(self.monsterinfo.saved_goal, self.monsterinfo.last_sighting);
|
||||
new1 = true;
|
||||
} else if ((self.monsterinfo.aiflags & Defines.AI_PURSUIT_LAST_SEEN) != 0) {
|
||||
self.monsterinfo.aiflags &= ~Defines.AI_PURSUIT_LAST_SEEN;
|
||||
marker = PlayerTrail.PickFirst(self);
|
||||
} else {
|
||||
marker = PlayerTrail.PickNext(self);
|
||||
}
|
||||
|
||||
if (marker != null) {
|
||||
Math3D.VectorCopy(marker.s.origin, self.monsterinfo.last_sighting);
|
||||
self.monsterinfo.trail_time = marker.timestamp;
|
||||
self.s.angles[Defines.YAW] = self.ideal_yaw = marker.s.angles[Defines.YAW];
|
||||
// dprint("heading is ");
|
||||
// dprint(ftos(self.ideal_yaw));
|
||||
// dprint("\n");
|
||||
// debug_drawline(self.origin, self.last_sighting, 52);
|
||||
new1 = true;
|
||||
}
|
||||
}
|
||||
|
||||
Math3D.VectorSubtract(self.s.origin, self.monsterinfo.last_sighting, v);
|
||||
d1 = Math3D.VectorLength(v);
|
||||
if (d1 <= dist) {
|
||||
self.monsterinfo.aiflags |= Defines.AI_PURSUE_NEXT;
|
||||
dist = d1;
|
||||
}
|
||||
|
||||
Math3D.VectorCopy(self.monsterinfo.last_sighting, self.goalentity.s.origin);
|
||||
|
||||
if (new1) {
|
||||
// gi.dprintf("checking for course correction\n");
|
||||
|
||||
tr = GameBase.gi.trace(self.s.origin, self.mins, self.maxs,
|
||||
self.monsterinfo.last_sighting, self,
|
||||
Defines.MASK_PLAYERSOLID);
|
||||
if (tr.fraction < 1) {
|
||||
Math3D.VectorSubtract(self.goalentity.s.origin, self.s.origin, v);
|
||||
d1 = Math3D.VectorLength(v);
|
||||
center = tr.fraction;
|
||||
d2 = d1 * ((center + 1) / 2);
|
||||
self.s.angles[Defines.YAW] = self.ideal_yaw = Math3D.vectoyaw(v);
|
||||
Math3D.AngleVectors(self.s.angles, v_forward, v_right, null);
|
||||
|
||||
Math3D.VectorSet(v, d2, -16, 0);
|
||||
Math3D.G_ProjectSource(self.s.origin, v, v_forward, v_right, left_target);
|
||||
tr = GameBase.gi.trace(self.s.origin, self.mins, self.maxs,
|
||||
left_target, self, Defines.MASK_PLAYERSOLID);
|
||||
left = tr.fraction;
|
||||
|
||||
Math3D.VectorSet(v, d2, 16, 0);
|
||||
Math3D.G_ProjectSource(self.s.origin, v, v_forward,
|
||||
v_right, right_target);
|
||||
tr = GameBase.gi.trace(self.s.origin, self.mins, self.maxs,
|
||||
right_target, self, Defines.MASK_PLAYERSOLID);
|
||||
right = tr.fraction;
|
||||
|
||||
center = (d1 * center) / d2;
|
||||
if (left >= center && left > right) {
|
||||
if (left < 1) {
|
||||
Math3D.VectorSet(v, d2 * left * 0.5f, -16f, 0f);
|
||||
Math3D.G_ProjectSource(self.s.origin, v, v_forward,
|
||||
v_right, left_target);
|
||||
// gi.dprintf("incomplete path, go part way and adjust again\n");
|
||||
}
|
||||
Math3D.VectorCopy(self.monsterinfo.last_sighting, self.monsterinfo.saved_goal);
|
||||
self.monsterinfo.aiflags |= Defines.AI_PURSUE_TEMP;
|
||||
Math3D.VectorCopy(left_target, self.goalentity.s.origin);
|
||||
Math3D.VectorCopy(left_target, self.monsterinfo.last_sighting);
|
||||
Math3D.VectorSubtract(self.goalentity.s.origin, self.s.origin, v);
|
||||
self.s.angles[Defines.YAW] = self.ideal_yaw = Math3D.vectoyaw(v);
|
||||
// gi.dprintf("adjusted left\n");
|
||||
// debug_drawline(self.origin, self.last_sighting, 152);
|
||||
} else if (right >= center && right > left) {
|
||||
if (right < 1) {
|
||||
Math3D.VectorSet(v, d2 * right * 0.5f, 16f, 0f);
|
||||
Math3D.G_ProjectSource(self.s.origin, v, v_forward,
|
||||
v_right, right_target);
|
||||
// gi.dprintf("incomplete path, go part way and adjust again\n");
|
||||
}
|
||||
Math3D.VectorCopy(self.monsterinfo.last_sighting, self.monsterinfo.saved_goal);
|
||||
self.monsterinfo.aiflags |= Defines.AI_PURSUE_TEMP;
|
||||
Math3D.VectorCopy(right_target, self.goalentity.s.origin);
|
||||
Math3D.VectorCopy(right_target, self.monsterinfo.last_sighting);
|
||||
Math3D.VectorSubtract(self.goalentity.s.origin, self.s.origin, v);
|
||||
self.s.angles[Defines.YAW] = self.ideal_yaw = Math3D.vectoyaw(v);
|
||||
// gi.dprintf("adjusted right\n");
|
||||
// debug_drawline(self.origin, self.last_sighting, 152);
|
||||
}
|
||||
}
|
||||
// else gi.dprintf("course was fine\n");
|
||||
}
|
||||
|
||||
M.M_MoveToGoal(self, dist);
|
||||
|
||||
GameUtil.G_FreeEdict(tempgoal);
|
||||
|
||||
if (self != null)
|
||||
self.goalentity = save;
|
||||
}
|
||||
};
|
||||
|
||||
static boolean enemy_vis;
|
||||
|
||||
static boolean enemy_infront;
|
||||
|
||||
static int enemy_range;
|
||||
|
||||
static float enemy_yaw;
|
||||
}
|
||||
658
src/main/java/lwjake2/game/GameBase.java
Normal file
658
src/main/java/lwjake2/game/GameBase.java
Normal file
@@ -0,0 +1,658 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/** Father of all GameObjects. */
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.client.M;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.server.SV;
|
||||
import lwjake2.server.SV_WORLD;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
@Slf4j
|
||||
public class GameBase {
|
||||
public static cplane_t dummyplane = new cplane_t();
|
||||
|
||||
public static game_locals_t game = new game_locals_t();
|
||||
|
||||
public static level_locals_t level = new level_locals_t();
|
||||
|
||||
public static game_import_t gi = new game_import_t();
|
||||
|
||||
public static spawn_temp_t st = new spawn_temp_t();
|
||||
|
||||
public static int sm_meat_index;
|
||||
|
||||
public static int snd_fry;
|
||||
|
||||
public static int meansOfDeath;
|
||||
|
||||
public static int num_edicts;
|
||||
|
||||
public static edict_t g_edicts[] = new edict_t[Defines.MAX_EDICTS];
|
||||
static {
|
||||
for (int n = 0; n < Defines.MAX_EDICTS; n++)
|
||||
g_edicts[n] = new edict_t(n);
|
||||
}
|
||||
|
||||
public static cvar_t deathmatch = new cvar_t();
|
||||
|
||||
public static cvar_t coop = new cvar_t();
|
||||
|
||||
public static cvar_t dmflags = new cvar_t();
|
||||
|
||||
public static cvar_t skill; // = new cvar_t();
|
||||
|
||||
public static cvar_t fraglimit = new cvar_t();
|
||||
|
||||
public static cvar_t timelimit = new cvar_t();
|
||||
|
||||
public static cvar_t password = new cvar_t();
|
||||
|
||||
public static cvar_t spectator_password = new cvar_t();
|
||||
|
||||
public static cvar_t needpass = new cvar_t();
|
||||
|
||||
public static cvar_t maxclients = new cvar_t();
|
||||
|
||||
public static cvar_t maxspectators = new cvar_t();
|
||||
|
||||
public static cvar_t maxentities = new cvar_t();
|
||||
|
||||
public static cvar_t g_select_empty = new cvar_t();
|
||||
|
||||
public static cvar_t filterban = new cvar_t();
|
||||
|
||||
public static cvar_t sv_maxvelocity = new cvar_t();
|
||||
|
||||
public static cvar_t sv_gravity = new cvar_t();
|
||||
|
||||
public static cvar_t sv_rollspeed = new cvar_t();
|
||||
|
||||
public static cvar_t sv_rollangle = new cvar_t();
|
||||
|
||||
public static cvar_t gun_x = new cvar_t();
|
||||
|
||||
public static cvar_t gun_y = new cvar_t();
|
||||
|
||||
public static cvar_t gun_z = new cvar_t();
|
||||
|
||||
public static cvar_t run_pitch = new cvar_t();
|
||||
|
||||
public static cvar_t run_roll = new cvar_t();
|
||||
|
||||
public static cvar_t bob_up = new cvar_t();
|
||||
|
||||
public static cvar_t bob_pitch = new cvar_t();
|
||||
|
||||
public static cvar_t bob_roll = new cvar_t();
|
||||
|
||||
public static cvar_t sv_cheats = new cvar_t();
|
||||
|
||||
public static cvar_t flood_msgs = new cvar_t();
|
||||
|
||||
public static cvar_t flood_persecond = new cvar_t();
|
||||
|
||||
public static cvar_t flood_waitdelay = new cvar_t();
|
||||
|
||||
public static cvar_t sv_maplist = new cvar_t();
|
||||
|
||||
public final static float STOP_EPSILON = 0.1f;
|
||||
|
||||
/**
|
||||
* Slide off of the impacting object returns the blocked flags (1 = floor, 2 =
|
||||
* step / wall).
|
||||
*/
|
||||
public static int ClipVelocity(float[] in, float[] normal, float[] out,
|
||||
float overbounce) {
|
||||
float backoff;
|
||||
float change;
|
||||
int i, blocked;
|
||||
|
||||
blocked = 0;
|
||||
if (normal[2] > 0)
|
||||
blocked |= 1; // floor
|
||||
if (normal[2] == 0.0f)
|
||||
blocked |= 2; // step
|
||||
|
||||
backoff = Math3D.DotProduct(in, normal) * overbounce;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
change = normal[i] * backoff;
|
||||
out[i] = in[i] - change;
|
||||
if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
|
||||
out[i] = 0;
|
||||
}
|
||||
|
||||
return blocked;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Searches all active entities for the next one that holds the matching
|
||||
* string at fieldofs (use the FOFS() macro) in the structure.
|
||||
*
|
||||
* Searches beginning at the edict after from, or the beginning if null null
|
||||
* will be returned if the end of the list is reached.
|
||||
*
|
||||
*/
|
||||
|
||||
public static EdictIterator G_Find(EdictIterator from, EdictFindFilter eff,
|
||||
String s) {
|
||||
|
||||
if (from == null)
|
||||
from = new EdictIterator(0);
|
||||
else
|
||||
from.i++;
|
||||
|
||||
for (; from.i < num_edicts; from.i++) {
|
||||
from.o = g_edicts[from.i];
|
||||
if (from.o.classname == null) {
|
||||
Com.Printf("edict with classname = null" + from.o.index);
|
||||
}
|
||||
|
||||
if (!from.o.inuse)
|
||||
continue;
|
||||
|
||||
if (eff.matches(from.o, s))
|
||||
return from;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// comfort version (rst)
|
||||
public static edict_t G_FindEdict(EdictIterator from, EdictFindFilter eff,
|
||||
String s) {
|
||||
EdictIterator ei = G_Find(from, eff, s);
|
||||
if (ei == null)
|
||||
return null;
|
||||
else
|
||||
return ei.o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns entities that have origins within a spherical area.
|
||||
*/
|
||||
public static EdictIterator findradius(EdictIterator from, float[] org,
|
||||
float rad) {
|
||||
float[] eorg = { 0, 0, 0 };
|
||||
int j;
|
||||
|
||||
if (from == null)
|
||||
from = new EdictIterator(0);
|
||||
else
|
||||
from.i++;
|
||||
|
||||
for (; from.i < num_edicts; from.i++) {
|
||||
from.o = g_edicts[from.i];
|
||||
if (!from.o.inuse)
|
||||
continue;
|
||||
|
||||
if (from.o.solid == Defines.SOLID_NOT)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
eorg[j] = org[j]
|
||||
- (from.o.s.origin[j] + (from.o.mins[j] + from.o.maxs[j]) * 0.5f);
|
||||
|
||||
if (Math3D.VectorLength(eorg) > rad)
|
||||
continue;
|
||||
return from;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches all active entities for the next one that holds the matching
|
||||
* string at fieldofs (use the FOFS() macro) in the structure.
|
||||
*
|
||||
* Searches beginning at the edict after from, or the beginning if null null
|
||||
* will be returned if the end of the list is reached.
|
||||
*/
|
||||
|
||||
public static int MAXCHOICES = 8;
|
||||
|
||||
public static edict_t G_PickTarget(String targetname) {
|
||||
int num_choices = 0;
|
||||
edict_t choice[] = new edict_t[MAXCHOICES];
|
||||
|
||||
if (targetname == null) {
|
||||
log.info("G_PickTarget called with null targetname");
|
||||
return null;
|
||||
}
|
||||
|
||||
EdictIterator es = null;
|
||||
|
||||
while ((es = G_Find(es, findByTarget, targetname)) != null) {
|
||||
choice[num_choices++] = es.o;
|
||||
if (num_choices == MAXCHOICES)
|
||||
break;
|
||||
}
|
||||
|
||||
if (num_choices == 0) {
|
||||
log.info("G_PickTarget: target {} not found", targetname);
|
||||
return null;
|
||||
}
|
||||
|
||||
return choice[Lib.rand() % num_choices];
|
||||
}
|
||||
|
||||
public static float[] VEC_UP = { 0, -1, 0 };
|
||||
|
||||
public static float[] MOVEDIR_UP = { 0, 0, 1 };
|
||||
|
||||
public static float[] VEC_DOWN = { 0, -2, 0 };
|
||||
|
||||
public static float[] MOVEDIR_DOWN = { 0, 0, -1 };
|
||||
|
||||
public static void G_SetMovedir(float[] angles, float[] movedir) {
|
||||
if (Math3D.VectorEquals(angles, VEC_UP)) {
|
||||
Math3D.VectorCopy(MOVEDIR_UP, movedir);
|
||||
} else if (Math3D.VectorEquals(angles, VEC_DOWN)) {
|
||||
Math3D.VectorCopy(MOVEDIR_DOWN, movedir);
|
||||
} else {
|
||||
Math3D.AngleVectors(angles, movedir, null, null);
|
||||
}
|
||||
|
||||
Math3D.VectorClear(angles);
|
||||
}
|
||||
|
||||
public static String G_CopyString(String in) {
|
||||
return new String(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* G_TouchTriggers
|
||||
*/
|
||||
|
||||
static edict_t touch[] = new edict_t[Defines.MAX_EDICTS];
|
||||
|
||||
public static void G_TouchTriggers(edict_t ent) {
|
||||
int i, num;
|
||||
edict_t hit;
|
||||
|
||||
// dead things don't activate triggers!
|
||||
if ((ent.client != null || (ent.svflags & Defines.SVF_MONSTER) != 0)
|
||||
&& (ent.health <= 0))
|
||||
return;
|
||||
|
||||
num = gi.BoxEdicts(ent.absmin, ent.absmax, touch, Defines.MAX_EDICTS,
|
||||
Defines.AREA_TRIGGERS);
|
||||
|
||||
// be careful, it is possible to have an entity in this
|
||||
// list removed before we get to it (killtriggered)
|
||||
for (i = 0; i < num; i++) {
|
||||
hit = touch[i];
|
||||
|
||||
if (!hit.inuse)
|
||||
continue;
|
||||
|
||||
if (hit.touch == null)
|
||||
continue;
|
||||
|
||||
hit.touch.touch(hit, ent, dummyplane, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static pushed_t pushed[] = new pushed_t[Defines.MAX_EDICTS];
|
||||
static {
|
||||
for (int n = 0; n < Defines.MAX_EDICTS; n++)
|
||||
pushed[n] = new pushed_t();
|
||||
}
|
||||
|
||||
public static int pushed_p;
|
||||
|
||||
public static edict_t obstacle;
|
||||
|
||||
public static int c_yes, c_no;
|
||||
|
||||
public static int STEPSIZE = 18;
|
||||
|
||||
/**
|
||||
* G_RunEntity
|
||||
*/
|
||||
public static void G_RunEntity(edict_t ent) {
|
||||
|
||||
if (ent.prethink != null)
|
||||
ent.prethink.think(ent);
|
||||
|
||||
switch ((int) ent.movetype) {
|
||||
case Defines.MOVETYPE_PUSH:
|
||||
case Defines.MOVETYPE_STOP:
|
||||
SV.SV_Physics_Pusher(ent);
|
||||
break;
|
||||
case Defines.MOVETYPE_NONE:
|
||||
SV.SV_Physics_None(ent);
|
||||
break;
|
||||
case Defines.MOVETYPE_NOCLIP:
|
||||
SV.SV_Physics_Noclip(ent);
|
||||
break;
|
||||
case Defines.MOVETYPE_STEP:
|
||||
SV.SV_Physics_Step(ent);
|
||||
break;
|
||||
case Defines.MOVETYPE_TOSS:
|
||||
case Defines.MOVETYPE_BOUNCE:
|
||||
case Defines.MOVETYPE_FLY:
|
||||
case Defines.MOVETYPE_FLYMISSILE:
|
||||
SV.SV_Physics_Toss(ent);
|
||||
break;
|
||||
default:
|
||||
gi.error("SV_Physics: bad movetype " + (int) ent.movetype);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearBounds(float[] mins, float[] maxs) {
|
||||
mins[0] = mins[1] = mins[2] = 99999;
|
||||
maxs[0] = maxs[1] = maxs[2] = -99999;
|
||||
}
|
||||
|
||||
public static void AddPointToBounds(float[] v, float[] mins, float[] maxs) {
|
||||
int i;
|
||||
float val;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
val = v[i];
|
||||
if (val < mins[i])
|
||||
mins[i] = val;
|
||||
if (val > maxs[i])
|
||||
maxs[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
public static EdictFindFilter findByTarget = new EdictFindFilter() {
|
||||
public boolean matches(edict_t e, String s) {
|
||||
if (e.targetname == null)
|
||||
return false;
|
||||
return e.targetname.equalsIgnoreCase(s);
|
||||
}
|
||||
};
|
||||
|
||||
public static EdictFindFilter findByClass = new EdictFindFilter() {
|
||||
public boolean matches(edict_t e, String s) {
|
||||
return e.classname.equalsIgnoreCase(s);
|
||||
}
|
||||
};
|
||||
|
||||
public static void ShutdownGame() {
|
||||
log.info("==== ShutdownGame ====");
|
||||
}
|
||||
|
||||
/**
|
||||
* ClientEndServerFrames.
|
||||
*/
|
||||
public static void ClientEndServerFrames() {
|
||||
int i;
|
||||
edict_t ent;
|
||||
|
||||
// calc the player views now that all pushing
|
||||
// and damage has been added
|
||||
for (i = 0; i < maxclients.value; i++) {
|
||||
ent = g_edicts[1 + i];
|
||||
if (!ent.inuse || null == ent.client)
|
||||
continue;
|
||||
PlayerView.ClientEndServerFrame(ent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the created target changelevel.
|
||||
*/
|
||||
public static edict_t CreateTargetChangeLevel(String map) {
|
||||
edict_t ent;
|
||||
|
||||
ent = GameUtil.G_Spawn();
|
||||
ent.classname = "target_changelevel";
|
||||
level.nextmap = map;
|
||||
ent.map = level.nextmap;
|
||||
return ent;
|
||||
}
|
||||
|
||||
/**
|
||||
* The timelimit or fraglimit has been exceeded.
|
||||
*/
|
||||
public static void EndDMLevel() {
|
||||
edict_t ent;
|
||||
//char * s, * t, * f;
|
||||
//static const char * seps = " ,\n\r";
|
||||
String s, t, f;
|
||||
String seps = " ,\n\r";
|
||||
|
||||
// stay on same level flag
|
||||
if (((int) dmflags.value & Defines.DF_SAME_LEVEL) != 0) {
|
||||
PlayerHud.BeginIntermission(CreateTargetChangeLevel(level.mapname));
|
||||
return;
|
||||
}
|
||||
|
||||
// see if it's in the map list
|
||||
if (sv_maplist.string.length() > 0) {
|
||||
s = sv_maplist.string;
|
||||
f = null;
|
||||
StringTokenizer tk = new StringTokenizer(s, seps);
|
||||
|
||||
while (tk.hasMoreTokens()){
|
||||
t = tk.nextToken();
|
||||
|
||||
// store first map
|
||||
if (f == null)
|
||||
f = t;
|
||||
|
||||
if (t.equalsIgnoreCase(level.mapname)) {
|
||||
// it's in the list, go to the next one
|
||||
if (!tk.hasMoreTokens()) {
|
||||
// end of list, go to first one
|
||||
if (f == null) // there isn't a first one, same level
|
||||
PlayerHud.BeginIntermission(CreateTargetChangeLevel(level.mapname));
|
||||
else
|
||||
PlayerHud.BeginIntermission(CreateTargetChangeLevel(f));
|
||||
} else
|
||||
PlayerHud.BeginIntermission(CreateTargetChangeLevel(tk.nextToken()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//not in the map list
|
||||
if (level.nextmap.length() > 0) // go to a specific map
|
||||
PlayerHud.BeginIntermission(CreateTargetChangeLevel(level.nextmap));
|
||||
else { // search for a changelevel
|
||||
EdictIterator edit = null;
|
||||
edit = G_Find(edit, findByClass, "target_changelevel");
|
||||
if (edit == null) { // the map designer didn't include a
|
||||
// changelevel,
|
||||
// so create a fake ent that goes back to the same level
|
||||
PlayerHud.BeginIntermission(CreateTargetChangeLevel(level.mapname));
|
||||
return;
|
||||
}
|
||||
ent = edit.o;
|
||||
PlayerHud.BeginIntermission(ent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CheckNeedPass.
|
||||
*/
|
||||
public static void CheckNeedPass() {
|
||||
int need;
|
||||
|
||||
// if password or spectator_password has changed, update needpass
|
||||
// as needed
|
||||
if (password.modified || spectator_password.modified) {
|
||||
password.modified = spectator_password.modified = false;
|
||||
|
||||
need = 0;
|
||||
|
||||
if ((password.string.length() > 0)
|
||||
&& 0 != Lib.Q_stricmp(password.string, "none"))
|
||||
need |= 1;
|
||||
if ((spectator_password.string.length() > 0)
|
||||
&& 0 != Lib.Q_stricmp(spectator_password.string, "none"))
|
||||
need |= 2;
|
||||
|
||||
gi.cvar_set("needpass", "" + need);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CheckDMRules.
|
||||
*/
|
||||
public static void CheckDMRules() {
|
||||
int i;
|
||||
gclient_t cl;
|
||||
|
||||
if (level.intermissiontime != 0)
|
||||
return;
|
||||
|
||||
if (0 == deathmatch.value)
|
||||
return;
|
||||
|
||||
if (timelimit.value != 0) {
|
||||
if (level.time >= timelimit.value * 60) {
|
||||
gi.bprintf(Defines.PRINT_HIGH, "Timelimit hit.\n");
|
||||
EndDMLevel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fraglimit.value != 0) {
|
||||
for (i = 0; i < maxclients.value; i++) {
|
||||
cl = game.clients[i];
|
||||
if (!g_edicts[i + 1].inuse)
|
||||
continue;
|
||||
|
||||
if (cl.resp.score >= fraglimit.value) {
|
||||
gi.bprintf(Defines.PRINT_HIGH, "Fraglimit hit.\n");
|
||||
EndDMLevel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exits a level.
|
||||
*/
|
||||
public static void ExitLevel() {
|
||||
int i;
|
||||
edict_t ent;
|
||||
|
||||
String command = "gamemap \"" + level.changemap + "\"\n";
|
||||
gi.AddCommandString(command);
|
||||
level.changemap = null;
|
||||
level.exitintermission = false;
|
||||
level.intermissiontime = 0;
|
||||
ClientEndServerFrames();
|
||||
|
||||
// clear some things before going to next level
|
||||
for (i = 0; i < maxclients.value; i++) {
|
||||
ent = g_edicts[1 + i];
|
||||
if (!ent.inuse)
|
||||
continue;
|
||||
if (ent.health > ent.client.pers.max_health)
|
||||
ent.health = ent.client.pers.max_health;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* G_RunFrame
|
||||
*
|
||||
* Advances the world by Defines.FRAMETIME (0.1) seconds.
|
||||
*/
|
||||
public static void G_RunFrame() {
|
||||
int i;
|
||||
edict_t ent;
|
||||
|
||||
level.framenum++;
|
||||
level.time = level.framenum * Defines.FRAMETIME;
|
||||
|
||||
// choose a client for monsters to target this frame
|
||||
GameAI.AI_SetSightClient();
|
||||
|
||||
// exit intermissions
|
||||
|
||||
if (level.exitintermission) {
|
||||
ExitLevel();
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// treat each object in turn
|
||||
// even the world gets a chance to think
|
||||
//
|
||||
|
||||
for (i = 0; i < num_edicts; i++) {
|
||||
ent = g_edicts[i];
|
||||
if (!ent.inuse)
|
||||
continue;
|
||||
|
||||
level.current_entity = ent;
|
||||
|
||||
Math3D.VectorCopy(ent.s.origin, ent.s.old_origin);
|
||||
|
||||
// if the ground entity moved, make sure we are still on it
|
||||
if ((ent.groundentity != null)
|
||||
&& (ent.groundentity.linkcount != ent.groundentity_linkcount)) {
|
||||
ent.groundentity = null;
|
||||
if (0 == (ent.flags & (Defines.FL_SWIM | Defines.FL_FLY))
|
||||
&& (ent.svflags & Defines.SVF_MONSTER) != 0) {
|
||||
M.M_CheckGround(ent);
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 0 && i <= maxclients.value) {
|
||||
PlayerClient.ClientBeginServerFrame(ent);
|
||||
continue;
|
||||
}
|
||||
|
||||
G_RunEntity(ent);
|
||||
}
|
||||
|
||||
// see if it is time to end a deathmatch
|
||||
CheckDMRules();
|
||||
|
||||
// see if needpass needs updated
|
||||
CheckNeedPass();
|
||||
|
||||
// build the playerstate_t structures for all players
|
||||
ClientEndServerFrames();
|
||||
}
|
||||
|
||||
/**
|
||||
* This return a pointer to the structure with all entry points and global
|
||||
* variables.
|
||||
*/
|
||||
|
||||
public static void GetGameApi(game_import_t imp) {
|
||||
gi = imp;
|
||||
gi.pointcontents = new pmove_t.PointContentsAdapter() {
|
||||
public int pointcontents(float[] o) {
|
||||
return SV_WORLD.SV_PointContents(o);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
183
src/main/java/lwjake2/game/GameChase.java
Normal file
183
src/main/java/lwjake2/game/GameChase.java
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.server.SV_WORLD;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
public class GameChase {
|
||||
|
||||
public static void UpdateChaseCam(edict_t ent) {
|
||||
float[] o = { 0, 0, 0 }, ownerv = { 0, 0, 0 }, goal = { 0, 0, 0 };
|
||||
edict_t targ;
|
||||
float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 };
|
||||
trace_t trace;
|
||||
int i;
|
||||
float[] oldgoal = { 0, 0, 0 };
|
||||
float[] angles = { 0, 0, 0 };
|
||||
|
||||
// is our chase target gone?
|
||||
if (!ent.client.chase_target.inuse
|
||||
|| ent.client.chase_target.client.resp.spectator) {
|
||||
edict_t old = ent.client.chase_target;
|
||||
ChaseNext(ent);
|
||||
if (ent.client.chase_target == old) {
|
||||
ent.client.chase_target = null;
|
||||
ent.client.ps.pmove.pm_flags &= ~pmove_t.PMF_NO_PREDICTION;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
targ = ent.client.chase_target;
|
||||
|
||||
Math3D.VectorCopy(targ.s.origin, ownerv);
|
||||
Math3D.VectorCopy(ent.s.origin, oldgoal);
|
||||
|
||||
ownerv[2] += targ.viewheight;
|
||||
|
||||
Math3D.VectorCopy(targ.client.v_angle, angles);
|
||||
if (angles[Defines.PITCH] > 56)
|
||||
angles[Defines.PITCH] = 56;
|
||||
Math3D.AngleVectors(angles, forward, right, null);
|
||||
Math3D.VectorNormalize(forward);
|
||||
Math3D.VectorMA(ownerv, -30, forward, o);
|
||||
|
||||
if (o[2] < targ.s.origin[2] + 20)
|
||||
o[2] = targ.s.origin[2] + 20;
|
||||
|
||||
// jump animation lifts
|
||||
if (targ.groundentity == null)
|
||||
o[2] += 16;
|
||||
|
||||
trace = GameBase.gi.trace(ownerv, Globals.vec3_origin,
|
||||
Globals.vec3_origin, o, targ, Defines.MASK_SOLID);
|
||||
|
||||
Math3D.VectorCopy(trace.endpos, goal);
|
||||
|
||||
Math3D.VectorMA(goal, 2, forward, goal);
|
||||
|
||||
// pad for floors and ceilings
|
||||
Math3D.VectorCopy(goal, o);
|
||||
o[2] += 6;
|
||||
trace = GameBase.gi.trace(goal, Globals.vec3_origin,
|
||||
Globals.vec3_origin, o, targ, Defines.MASK_SOLID);
|
||||
if (trace.fraction < 1) {
|
||||
Math3D.VectorCopy(trace.endpos, goal);
|
||||
goal[2] -= 6;
|
||||
}
|
||||
|
||||
Math3D.VectorCopy(goal, o);
|
||||
o[2] -= 6;
|
||||
trace = GameBase.gi.trace(goal, Globals.vec3_origin,
|
||||
Globals.vec3_origin, o, targ, Defines.MASK_SOLID);
|
||||
if (trace.fraction < 1) {
|
||||
Math3D.VectorCopy(trace.endpos, goal);
|
||||
goal[2] += 6;
|
||||
}
|
||||
|
||||
if (targ.deadflag != 0)
|
||||
ent.client.ps.pmove.pm_type = Defines.PM_DEAD;
|
||||
else
|
||||
ent.client.ps.pmove.pm_type = Defines.PM_FREEZE;
|
||||
|
||||
Math3D.VectorCopy(goal, ent.s.origin);
|
||||
for (i = 0; i < 3; i++)
|
||||
ent.client.ps.pmove.delta_angles[i] = (short) Math3D
|
||||
.ANGLE2SHORT(targ.client.v_angle[i]
|
||||
- ent.client.resp.cmd_angles[i]);
|
||||
|
||||
if (targ.deadflag != 0) {
|
||||
ent.client.ps.viewangles[Defines.ROLL] = 40;
|
||||
ent.client.ps.viewangles[Defines.PITCH] = -15;
|
||||
ent.client.ps.viewangles[Defines.YAW] = targ.client.killer_yaw;
|
||||
} else {
|
||||
Math3D.VectorCopy(targ.client.v_angle, ent.client.ps.viewangles);
|
||||
Math3D.VectorCopy(targ.client.v_angle, ent.client.v_angle);
|
||||
}
|
||||
|
||||
ent.viewheight = 0;
|
||||
ent.client.ps.pmove.pm_flags |= pmove_t.PMF_NO_PREDICTION;
|
||||
SV_WORLD.SV_LinkEdict(ent);
|
||||
}
|
||||
|
||||
public static void ChaseNext(edict_t ent) {
|
||||
int i;
|
||||
edict_t e;
|
||||
|
||||
if (null == ent.client.chase_target)
|
||||
return;
|
||||
|
||||
i = ent.client.chase_target.index;
|
||||
do {
|
||||
i++;
|
||||
if (i > GameBase.maxclients.value)
|
||||
i = 1;
|
||||
e = GameBase.g_edicts[i];
|
||||
|
||||
if (!e.inuse)
|
||||
continue;
|
||||
if (!e.client.resp.spectator)
|
||||
break;
|
||||
} while (e != ent.client.chase_target);
|
||||
|
||||
ent.client.chase_target = e;
|
||||
ent.client.update_chase = true;
|
||||
}
|
||||
|
||||
public static void ChasePrev(edict_t ent) {
|
||||
int i;
|
||||
edict_t e;
|
||||
|
||||
if (ent.client.chase_target == null)
|
||||
return;
|
||||
|
||||
i = ent.client.chase_target.index;
|
||||
do {
|
||||
i--;
|
||||
if (i < 1)
|
||||
i = (int) GameBase.maxclients.value;
|
||||
e = GameBase.g_edicts[i];
|
||||
if (!e.inuse)
|
||||
continue;
|
||||
if (!e.client.resp.spectator)
|
||||
break;
|
||||
} while (e != ent.client.chase_target);
|
||||
|
||||
ent.client.chase_target = e;
|
||||
ent.client.update_chase = true;
|
||||
}
|
||||
|
||||
public static void GetChaseTarget(edict_t ent) {
|
||||
int i;
|
||||
edict_t other;
|
||||
|
||||
for (i = 1; i <= GameBase.maxclients.value; i++) {
|
||||
other = GameBase.g_edicts[i];
|
||||
if (other.inuse && !other.client.resp.spectator) {
|
||||
ent.client.chase_target = other;
|
||||
ent.client.update_chase = true;
|
||||
UpdateChaseCam(ent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
GameBase.gi.centerprintf(ent, "No other players to chase.");
|
||||
}
|
||||
}
|
||||
548
src/main/java/lwjake2/game/GameCombat.java
Normal file
548
src/main/java/lwjake2/game/GameCombat.java
Normal file
@@ -0,0 +1,548 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
public class GameCombat {
|
||||
|
||||
/**
|
||||
* CanDamage
|
||||
*
|
||||
* Returns true if the inflictor can directly damage the target. Used for
|
||||
* explosions and melee attacks.
|
||||
*/
|
||||
static boolean CanDamage(edict_t targ, edict_t inflictor) {
|
||||
float[] dest = { 0, 0, 0 };
|
||||
trace_t trace;
|
||||
|
||||
// bmodels need special checking because their origin is 0,0,0
|
||||
if (targ.movetype == Defines.MOVETYPE_PUSH) {
|
||||
Math3D.VectorAdd(targ.absmin, targ.absmax, dest);
|
||||
Math3D.VectorScale(dest, 0.5f, dest);
|
||||
trace = GameBase.gi.trace(inflictor.s.origin, Globals.vec3_origin,
|
||||
Globals.vec3_origin, dest, inflictor, Defines.MASK_SOLID);
|
||||
if (trace.fraction == 1.0f)
|
||||
return true;
|
||||
if (trace.ent == targ)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
trace = GameBase.gi.trace(inflictor.s.origin, Globals.vec3_origin,
|
||||
Globals.vec3_origin, targ.s.origin, inflictor,
|
||||
Defines.MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
Math3D.VectorCopy(targ.s.origin, dest);
|
||||
dest[0] += 15.0;
|
||||
dest[1] += 15.0;
|
||||
trace = GameBase.gi.trace(inflictor.s.origin, Globals.vec3_origin,
|
||||
Globals.vec3_origin, dest, inflictor, Defines.MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
Math3D.VectorCopy(targ.s.origin, dest);
|
||||
dest[0] += 15.0;
|
||||
dest[1] -= 15.0;
|
||||
trace = GameBase.gi.trace(inflictor.s.origin, Globals.vec3_origin,
|
||||
Globals.vec3_origin, dest, inflictor, Defines.MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
Math3D.VectorCopy(targ.s.origin, dest);
|
||||
dest[0] -= 15.0;
|
||||
dest[1] += 15.0;
|
||||
trace = GameBase.gi.trace(inflictor.s.origin, Globals.vec3_origin,
|
||||
Globals.vec3_origin, dest, inflictor, Defines.MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
Math3D.VectorCopy(targ.s.origin, dest);
|
||||
dest[0] -= 15.0;
|
||||
dest[1] -= 15.0;
|
||||
trace = GameBase.gi.trace(inflictor.s.origin, Globals.vec3_origin,
|
||||
Globals.vec3_origin, dest, inflictor, Defines.MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Killed.
|
||||
*/
|
||||
public static void Killed(edict_t targ, edict_t inflictor,
|
||||
edict_t attacker, int damage, float[] point) {
|
||||
Com.DPrintf("Killing a " + targ.classname + "\n");
|
||||
if (targ.health < -999)
|
||||
targ.health = -999;
|
||||
|
||||
targ.enemy = attacker;
|
||||
|
||||
if ((targ.svflags & Defines.SVF_MONSTER) != 0
|
||||
&& (targ.deadflag != Defines.DEAD_DEAD)) {
|
||||
// targ.svflags |= SVF_DEADMONSTER; // now treat as a different
|
||||
// content type
|
||||
if (0 == (targ.monsterinfo.aiflags & Defines.AI_GOOD_GUY)) {
|
||||
GameBase.level.killed_monsters++;
|
||||
if (GameBase.coop.value != 0 && attacker.client != null)
|
||||
attacker.client.resp.score++;
|
||||
// medics won't heal monsters that they kill themselves
|
||||
if (attacker.classname.equals("monster_medic"))
|
||||
targ.owner = attacker;
|
||||
}
|
||||
}
|
||||
|
||||
if (targ.movetype == Defines.MOVETYPE_PUSH
|
||||
|| targ.movetype == Defines.MOVETYPE_STOP
|
||||
|| targ.movetype == Defines.MOVETYPE_NONE) { // doors, triggers,
|
||||
// etc
|
||||
targ.die.die(targ, inflictor, attacker, damage, point);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((targ.svflags & Defines.SVF_MONSTER) != 0
|
||||
&& (targ.deadflag != Defines.DEAD_DEAD)) {
|
||||
targ.touch = null;
|
||||
Monster.monster_death_use(targ);
|
||||
}
|
||||
|
||||
targ.die.die(targ, inflictor, attacker, damage, point);
|
||||
}
|
||||
|
||||
/**
|
||||
* SpawnDamage.
|
||||
*/
|
||||
static void SpawnDamage(int type, float[] origin, float[] normal, int damage) {
|
||||
if (damage > 255)
|
||||
damage = 255;
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(type);
|
||||
// gi.WriteByte (damage);
|
||||
GameBase.gi.WritePosition(origin);
|
||||
GameBase.gi.WriteDir(normal);
|
||||
GameBase.gi.multicast(origin, Defines.MULTICAST_PVS);
|
||||
}
|
||||
|
||||
static int CheckPowerArmor(edict_t ent, float[] point, float[] normal,
|
||||
int damage, int dflags) {
|
||||
gclient_t client;
|
||||
int save;
|
||||
int power_armor_type;
|
||||
int index = 0;
|
||||
int damagePerCell;
|
||||
int pa_te_type;
|
||||
int power = 0;
|
||||
int power_used;
|
||||
|
||||
if (damage == 0)
|
||||
return 0;
|
||||
|
||||
client = ent.client;
|
||||
|
||||
if ((dflags & Defines.DAMAGE_NO_ARMOR) != 0)
|
||||
return 0;
|
||||
|
||||
if (client != null) {
|
||||
power_armor_type = GameItems.PowerArmorType(ent);
|
||||
if (power_armor_type != Defines.POWER_ARMOR_NONE) {
|
||||
index = GameItems.ITEM_INDEX(GameItems.FindItem("Cells"));
|
||||
power = client.pers.inventory[index];
|
||||
}
|
||||
} else if ((ent.svflags & Defines.SVF_MONSTER) != 0) {
|
||||
power_armor_type = ent.monsterinfo.power_armor_type;
|
||||
power = ent.monsterinfo.power_armor_power;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
if (power_armor_type == Defines.POWER_ARMOR_NONE)
|
||||
return 0;
|
||||
if (power == 0)
|
||||
return 0;
|
||||
|
||||
if (power_armor_type == Defines.POWER_ARMOR_SCREEN) {
|
||||
float[] vec = { 0, 0, 0 };
|
||||
float dot;
|
||||
float[] forward = { 0, 0, 0 };
|
||||
|
||||
// only works if damage point is in front
|
||||
Math3D.AngleVectors(ent.s.angles, forward, null, null);
|
||||
Math3D.VectorSubtract(point, ent.s.origin, vec);
|
||||
Math3D.VectorNormalize(vec);
|
||||
dot = Math3D.DotProduct(vec, forward);
|
||||
if (dot <= 0.3)
|
||||
return 0;
|
||||
|
||||
damagePerCell = 1;
|
||||
pa_te_type = Defines.TE_SCREEN_SPARKS;
|
||||
damage = damage / 3;
|
||||
} else {
|
||||
damagePerCell = 2;
|
||||
pa_te_type = Defines.TE_SHIELD_SPARKS;
|
||||
damage = (2 * damage) / 3;
|
||||
}
|
||||
|
||||
save = power * damagePerCell;
|
||||
|
||||
if (save == 0)
|
||||
return 0;
|
||||
if (save > damage)
|
||||
save = damage;
|
||||
|
||||
SpawnDamage(pa_te_type, point, normal, save);
|
||||
ent.powerarmor_time = GameBase.level.time + 0.2f;
|
||||
|
||||
power_used = save / damagePerCell;
|
||||
|
||||
if (client != null)
|
||||
client.pers.inventory[index] -= power_used;
|
||||
else
|
||||
ent.monsterinfo.power_armor_power -= power_used;
|
||||
return save;
|
||||
}
|
||||
|
||||
static int CheckArmor(edict_t ent, float[] point, float[] normal,
|
||||
int damage, int te_sparks, int dflags) {
|
||||
gclient_t client;
|
||||
int save;
|
||||
int index;
|
||||
gitem_t armor;
|
||||
|
||||
if (damage == 0)
|
||||
return 0;
|
||||
|
||||
client = ent.client;
|
||||
|
||||
if (client == null)
|
||||
return 0;
|
||||
|
||||
if ((dflags & Defines.DAMAGE_NO_ARMOR) != 0)
|
||||
return 0;
|
||||
|
||||
index = GameItems.ArmorIndex(ent);
|
||||
|
||||
if (index == 0)
|
||||
return 0;
|
||||
|
||||
armor = GameItems.GetItemByIndex(index);
|
||||
gitem_armor_t garmor = (gitem_armor_t) armor.info;
|
||||
|
||||
if (0 != (dflags & Defines.DAMAGE_ENERGY))
|
||||
save = (int) Math.ceil(garmor.energy_protection * damage);
|
||||
else
|
||||
save = (int) Math.ceil(garmor.normal_protection * damage);
|
||||
|
||||
if (save >= client.pers.inventory[index])
|
||||
save = client.pers.inventory[index];
|
||||
|
||||
if (save == 0)
|
||||
return 0;
|
||||
|
||||
client.pers.inventory[index] -= save;
|
||||
SpawnDamage(te_sparks, point, normal, save);
|
||||
|
||||
return save;
|
||||
}
|
||||
|
||||
public static void M_ReactToDamage(edict_t targ, edict_t attacker) {
|
||||
if ((null != attacker.client)
|
||||
&& 0 != (attacker.svflags & Defines.SVF_MONSTER))
|
||||
return;
|
||||
|
||||
if (attacker == targ || attacker == targ.enemy)
|
||||
return;
|
||||
|
||||
// if we are a good guy monster and our attacker is a player
|
||||
// or another good guy, do not get mad at them
|
||||
if (0 != (targ.monsterinfo.aiflags & Defines.AI_GOOD_GUY)) {
|
||||
if (attacker.client != null
|
||||
|| (attacker.monsterinfo.aiflags & Defines.AI_GOOD_GUY) != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// we now know that we are not both good guys
|
||||
|
||||
// if attacker is a client, get mad at them because he's good and we're
|
||||
// not
|
||||
if (attacker.client != null) {
|
||||
targ.monsterinfo.aiflags &= ~Defines.AI_SOUND_TARGET;
|
||||
|
||||
// this can only happen in coop (both new and old enemies are
|
||||
// clients)
|
||||
// only switch if can't see the current enemy
|
||||
if (targ.enemy != null && targ.enemy.client != null) {
|
||||
if (GameUtil.visible(targ, targ.enemy)) {
|
||||
targ.oldenemy = attacker;
|
||||
return;
|
||||
}
|
||||
targ.oldenemy = targ.enemy;
|
||||
}
|
||||
targ.enemy = attacker;
|
||||
if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
|
||||
GameUtil.FoundTarget(targ);
|
||||
return;
|
||||
}
|
||||
|
||||
// it's the same base (walk/swim/fly) type and a different classname and
|
||||
// it's not a tank
|
||||
// (they spray too much), get mad at them
|
||||
if (((targ.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == (attacker.flags & (Defines.FL_FLY | Defines.FL_SWIM)))
|
||||
&& (!(targ.classname.equals(attacker.classname)))
|
||||
&& (!(attacker.classname.equals("monster_tank")))
|
||||
&& (!(attacker.classname.equals("monster_supertank")))
|
||||
&& (!(attacker.classname.equals("monster_makron")))
|
||||
&& (!(attacker.classname.equals("monster_jorg")))) {
|
||||
if (targ.enemy != null && targ.enemy.client != null)
|
||||
targ.oldenemy = targ.enemy;
|
||||
targ.enemy = attacker;
|
||||
if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
|
||||
GameUtil.FoundTarget(targ);
|
||||
}
|
||||
// if they *meant* to shoot us, then shoot back
|
||||
else if (attacker.enemy == targ) {
|
||||
if (targ.enemy != null && targ.enemy.client != null)
|
||||
targ.oldenemy = targ.enemy;
|
||||
targ.enemy = attacker;
|
||||
if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
|
||||
GameUtil.FoundTarget(targ);
|
||||
}
|
||||
// otherwise get mad at whoever they are mad at (help our buddy) unless
|
||||
// it is us!
|
||||
else if (attacker.enemy != null && attacker.enemy != targ) {
|
||||
if (targ.enemy != null && targ.enemy.client != null)
|
||||
targ.oldenemy = targ.enemy;
|
||||
targ.enemy = attacker.enemy;
|
||||
if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
|
||||
GameUtil.FoundTarget(targ);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean CheckTeamDamage(edict_t targ, edict_t attacker) {
|
||||
//FIXME make the next line real and uncomment this block
|
||||
// if ((ability to damage a teammate == OFF) && (targ's team ==
|
||||
// attacker's team))
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* T_RadiusDamage.
|
||||
*/
|
||||
static void T_RadiusDamage(edict_t inflictor, edict_t attacker,
|
||||
float damage, edict_t ignore, float radius, int mod) {
|
||||
float points;
|
||||
EdictIterator edictit = null;
|
||||
|
||||
float[] v = { 0, 0, 0 };
|
||||
float[] dir = { 0, 0, 0 };
|
||||
|
||||
while ((edictit = GameBase.findradius(edictit, inflictor.s.origin,
|
||||
radius)) != null) {
|
||||
edict_t ent = edictit.o;
|
||||
if (ent == ignore)
|
||||
continue;
|
||||
if (ent.takedamage == 0)
|
||||
continue;
|
||||
|
||||
Math3D.VectorAdd(ent.mins, ent.maxs, v);
|
||||
Math3D.VectorMA(ent.s.origin, 0.5f, v, v);
|
||||
Math3D.VectorSubtract(inflictor.s.origin, v, v);
|
||||
points = damage - 0.5f * Math3D.VectorLength(v);
|
||||
if (ent == attacker)
|
||||
points = points * 0.5f;
|
||||
if (points > 0) {
|
||||
if (CanDamage(ent, inflictor)) {
|
||||
Math3D.VectorSubtract(ent.s.origin, inflictor.s.origin, dir);
|
||||
T_Damage(ent, inflictor, attacker, dir, inflictor.s.origin,
|
||||
Globals.vec3_origin, (int) points, (int) points,
|
||||
Defines.DAMAGE_RADIUS, mod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void T_Damage(edict_t targ, edict_t inflictor,
|
||||
edict_t attacker, float[] dir, float[] point, float[] normal,
|
||||
int damage, int knockback, int dflags, int mod) {
|
||||
gclient_t client;
|
||||
int take;
|
||||
int save;
|
||||
int asave;
|
||||
int psave;
|
||||
int te_sparks;
|
||||
|
||||
if (targ.takedamage == 0)
|
||||
return;
|
||||
|
||||
// friendly fire avoidance
|
||||
// if enabled you can't hurt teammates (but you can hurt yourself)
|
||||
// knockback still occurs
|
||||
if ((targ != attacker)
|
||||
&& ((GameBase.deathmatch.value != 0 && 0 != ((int) (GameBase.dmflags.value) & (Defines.DF_MODELTEAMS | Defines.DF_SKINTEAMS))) || GameBase.coop.value != 0)) {
|
||||
if (GameUtil.OnSameTeam(targ, attacker)) {
|
||||
if (((int) (GameBase.dmflags.value) & Defines.DF_NO_FRIENDLY_FIRE) != 0)
|
||||
damage = 0;
|
||||
else
|
||||
mod |= Defines.MOD_FRIENDLY_FIRE;
|
||||
}
|
||||
}
|
||||
GameBase.meansOfDeath = mod;
|
||||
|
||||
// easy mode takes half damage
|
||||
if (GameBase.skill.value == 0 && GameBase.deathmatch.value == 0
|
||||
&& targ.client != null) {
|
||||
damage *= 0.5;
|
||||
if (damage == 0)
|
||||
damage = 1;
|
||||
}
|
||||
|
||||
client = targ.client;
|
||||
|
||||
if ((dflags & Defines.DAMAGE_BULLET) != 0)
|
||||
te_sparks = Defines.TE_BULLET_SPARKS;
|
||||
else
|
||||
te_sparks = Defines.TE_SPARKS;
|
||||
|
||||
Math3D.VectorNormalize(dir);
|
||||
|
||||
// bonus damage for suprising a monster
|
||||
if (0 == (dflags & Defines.DAMAGE_RADIUS)
|
||||
&& (targ.svflags & Defines.SVF_MONSTER) != 0
|
||||
&& (attacker.client != null) && (targ.enemy == null)
|
||||
&& (targ.health > 0))
|
||||
damage *= 2;
|
||||
|
||||
if ((targ.flags & Defines.FL_NO_KNOCKBACK) != 0)
|
||||
knockback = 0;
|
||||
|
||||
// figure momentum add
|
||||
if (0 == (dflags & Defines.DAMAGE_NO_KNOCKBACK)) {
|
||||
if ((knockback != 0) && (targ.movetype != Defines.MOVETYPE_NONE)
|
||||
&& (targ.movetype != Defines.MOVETYPE_BOUNCE)
|
||||
&& (targ.movetype != Defines.MOVETYPE_PUSH)
|
||||
&& (targ.movetype != Defines.MOVETYPE_STOP)) {
|
||||
float[] kvel = { 0, 0, 0 };
|
||||
float mass;
|
||||
|
||||
if (targ.mass < 50)
|
||||
mass = 50;
|
||||
else
|
||||
mass = targ.mass;
|
||||
|
||||
if (targ.client != null && attacker == targ)
|
||||
Math3D.VectorScale(dir, 1600.0f * (float) knockback / mass,
|
||||
kvel);
|
||||
// the rocket jump hack...
|
||||
else
|
||||
Math3D.VectorScale(dir, 500.0f * (float) knockback / mass,
|
||||
kvel);
|
||||
|
||||
Math3D.VectorAdd(targ.velocity, kvel, targ.velocity);
|
||||
}
|
||||
}
|
||||
|
||||
take = damage;
|
||||
save = 0;
|
||||
|
||||
// check for godmode
|
||||
if ((targ.flags & Defines.FL_GODMODE) != 0
|
||||
&& 0 == (dflags & Defines.DAMAGE_NO_PROTECTION)) {
|
||||
take = 0;
|
||||
save = damage;
|
||||
SpawnDamage(te_sparks, point, normal, save);
|
||||
}
|
||||
|
||||
// check for invincibility
|
||||
if ((client != null && client.invincible_framenum > GameBase.level.framenum)
|
||||
&& 0 == (dflags & Defines.DAMAGE_NO_PROTECTION)) {
|
||||
if (targ.pain_debounce_time < GameBase.level.time) {
|
||||
GameBase.gi.sound(targ, Defines.CHAN_ITEM, GameBase.gi
|
||||
.soundindex("items/protect4.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
targ.pain_debounce_time = GameBase.level.time + 2;
|
||||
}
|
||||
take = 0;
|
||||
save = damage;
|
||||
}
|
||||
|
||||
psave = CheckPowerArmor(targ, point, normal, take, dflags);
|
||||
take -= psave;
|
||||
|
||||
asave = CheckArmor(targ, point, normal, take, te_sparks, dflags);
|
||||
take -= asave;
|
||||
|
||||
// treat cheat/powerup savings the same as armor
|
||||
asave += save;
|
||||
|
||||
// team damage avoidance
|
||||
if (0 == (dflags & Defines.DAMAGE_NO_PROTECTION)
|
||||
&& CheckTeamDamage(targ, attacker))
|
||||
return;
|
||||
|
||||
// do the damage
|
||||
if (take != 0) {
|
||||
if (0 != (targ.svflags & Defines.SVF_MONSTER) || (client != null))
|
||||
SpawnDamage(Defines.TE_BLOOD, point, normal, take);
|
||||
else
|
||||
SpawnDamage(te_sparks, point, normal, take);
|
||||
|
||||
targ.health = targ.health - take;
|
||||
|
||||
if (targ.health <= 0) {
|
||||
if ((targ.svflags & Defines.SVF_MONSTER) != 0
|
||||
|| (client != null))
|
||||
targ.flags |= Defines.FL_NO_KNOCKBACK;
|
||||
Killed(targ, inflictor, attacker, take, point);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((targ.svflags & Defines.SVF_MONSTER) != 0) {
|
||||
M_ReactToDamage(targ, attacker);
|
||||
if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)
|
||||
&& (take != 0)) {
|
||||
targ.pain.pain(targ, attacker, knockback, take);
|
||||
// nightmare mode monsters don't go into pain frames often
|
||||
if (GameBase.skill.value == 3)
|
||||
targ.pain_debounce_time = GameBase.level.time + 5;
|
||||
}
|
||||
} else if (client != null) {
|
||||
if (((targ.flags & Defines.FL_GODMODE) == 0) && (take != 0))
|
||||
targ.pain.pain(targ, attacker, knockback, take);
|
||||
} else if (take != 0) {
|
||||
if (targ.pain != null)
|
||||
targ.pain.pain(targ, attacker, knockback, take);
|
||||
}
|
||||
|
||||
// add to the damage inflicted on a player this frame
|
||||
// the total will be turned into screen blends and view angle kicks
|
||||
// at the end of the frame
|
||||
if (client != null) {
|
||||
client.damage_parmor += psave;
|
||||
client.damage_armor += asave;
|
||||
client.damage_blood += take;
|
||||
client.damage_knockback += knockback;
|
||||
Math3D.VectorCopy(point, client.damage_from);
|
||||
}
|
||||
}
|
||||
}
|
||||
2206
src/main/java/lwjake2/game/GameFunc.java
Normal file
2206
src/main/java/lwjake2/game/GameFunc.java
Normal file
File diff suppressed because it is too large
Load Diff
753
src/main/java/lwjake2/game/GameItemList.java
Normal file
753
src/main/java/lwjake2/game/GameItemList.java
Normal file
@@ -0,0 +1,753 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
|
||||
public class GameItemList {
|
||||
|
||||
// RST: this was separated in the java conversion from the g_item.c
|
||||
// because all adapters have to be created in the other
|
||||
// classes before this class can be loaded.
|
||||
|
||||
public static gitem_t itemlist[] = {
|
||||
//leave index 0 alone
|
||||
new gitem_t(null, null, null, null, null, null, null, 0, null,
|
||||
null, null, 0, 0, null, 0, 0, null, 0, null),
|
||||
|
||||
//
|
||||
// ARMOR
|
||||
//
|
||||
new gitem_t(
|
||||
|
||||
/**
|
||||
* QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
|
||||
"item_armor_body", GameItems.Pickup_Armor, null, null, null,
|
||||
"misc/ar1_pkup.wav", "models/items/armor/body/tris.md2",
|
||||
Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"i_bodyarmor",
|
||||
/* pickup */
|
||||
"Body Armor",
|
||||
/* width */
|
||||
3, 0, null, Defines.IT_ARMOR, 0, GameItems.bodyarmor_info,
|
||||
Defines.ARMOR_BODY,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("item_armor_combat", GameItems.Pickup_Armor, null, null, null,
|
||||
"misc/ar1_pkup.wav", "models/items/armor/combat/tris.md2",
|
||||
Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"i_combatarmor",
|
||||
/* pickup */
|
||||
"Combat Armor",
|
||||
/* width */
|
||||
3, 0, null, Defines.IT_ARMOR, 0, GameItems.combatarmor_info,
|
||||
Defines.ARMOR_COMBAT,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED item_armor_jacket (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("item_armor_jacket", GameItems.Pickup_Armor, null, null, null,
|
||||
"misc/ar1_pkup.wav", "models/items/armor/jacket/tris.md2",
|
||||
Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"i_jacketarmor",
|
||||
/* pickup */
|
||||
"Jacket Armor",
|
||||
/* width */
|
||||
3, 0, null, Defines.IT_ARMOR, 0, GameItems.jacketarmor_info,
|
||||
Defines.ARMOR_JACKET,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("item_armor_shard", GameItems.Pickup_Armor, null, null, null,
|
||||
"misc/ar2_pkup.wav", "models/items/armor/shard/tris.md2",
|
||||
Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"i_jacketarmor",
|
||||
/* pickup */
|
||||
"Armor Shard",
|
||||
/* width */
|
||||
3, 0, null, Defines.IT_ARMOR, 0, null, Defines.ARMOR_SHARD,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED item_power_screen (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("item_power_screen", GameItems.Pickup_PowerArmor, GameItems.Use_PowerArmor,
|
||||
GameItems.Drop_PowerArmor, null, "misc/ar3_pkup.wav",
|
||||
"models/items/armor/screen/tris.md2", Defines.EF_ROTATE,
|
||||
null,
|
||||
/* icon */
|
||||
"i_powerscreen",
|
||||
/* pickup */
|
||||
"Power Screen",
|
||||
/* width */
|
||||
0, 60, null, Defines.IT_ARMOR, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED item_power_shield (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("item_power_shield", GameItems.Pickup_PowerArmor, GameItems.Use_PowerArmor,
|
||||
GameItems.Drop_PowerArmor, null, "misc/ar3_pkup.wav",
|
||||
"models/items/armor/shield/tris.md2", Defines.EF_ROTATE,
|
||||
null,
|
||||
/* icon */
|
||||
"i_powershield",
|
||||
/* pickup */
|
||||
"Power Shield",
|
||||
/* width */
|
||||
0, 60, null, Defines.IT_ARMOR, 0, null, 0,
|
||||
/* precache */
|
||||
"misc/power2.wav misc/power1.wav"),
|
||||
|
||||
//
|
||||
// WEAPONS
|
||||
//
|
||||
|
||||
/*
|
||||
* weapon_blaster (.3 .3 1) (-16 -16 -16) (16 16 16) always owned,
|
||||
* never in the world
|
||||
*/
|
||||
new gitem_t("weapon_blaster", null, PlayerWeapon.Use_Weapon, null,
|
||||
PlayerWeapon.Weapon_Blaster, "misc/w_pkup.wav", null, 0,
|
||||
"models/weapons/v_blast/tris.md2",
|
||||
/* icon */
|
||||
"w_blaster",
|
||||
/* pickup */
|
||||
"Blaster", 0, 0, null, Defines.IT_WEAPON
|
||||
| Defines.IT_STAY_COOP, Defines.WEAP_BLASTER, null,
|
||||
0,
|
||||
/* precache */
|
||||
"weapons/blastf1a.wav misc/lasfly.wav"),
|
||||
|
||||
/*
|
||||
* QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("weapon_shotgun", PlayerWeapon.Pickup_Weapon,
|
||||
PlayerWeapon.Use_Weapon, PlayerWeapon.Drop_Weapon,
|
||||
PlayerWeapon.Weapon_Shotgun, "misc/w_pkup.wav",
|
||||
"models/weapons/g_shotg/tris.md2", Defines.EF_ROTATE,
|
||||
"models/weapons/v_shotg/tris.md2",
|
||||
/* icon */
|
||||
"w_shotgun",
|
||||
/* pickup */
|
||||
"Shotgun", 0, 1, "Shells", Defines.IT_WEAPON
|
||||
| Defines.IT_STAY_COOP, Defines.WEAP_SHOTGUN, null,
|
||||
0,
|
||||
/* precache */
|
||||
"weapons/shotgf1b.wav weapons/shotgr1b.wav"),
|
||||
|
||||
/*
|
||||
* QUAKED weapon_supershotgun (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("weapon_supershotgun", PlayerWeapon.Pickup_Weapon,
|
||||
PlayerWeapon.Use_Weapon, PlayerWeapon.Drop_Weapon,
|
||||
PlayerWeapon.Weapon_SuperShotgun, "misc/w_pkup.wav",
|
||||
"models/weapons/g_shotg2/tris.md2", Defines.EF_ROTATE,
|
||||
"models/weapons/v_shotg2/tris.md2",
|
||||
/* icon */
|
||||
"w_sshotgun",
|
||||
/* pickup */
|
||||
"Super Shotgun", 0, 2, "Shells", Defines.IT_WEAPON
|
||||
| Defines.IT_STAY_COOP, Defines.WEAP_SUPERSHOTGUN,
|
||||
null, 0,
|
||||
/* precache */
|
||||
"weapons/sshotf1b.wav"),
|
||||
|
||||
/*
|
||||
* QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t(
|
||||
"weapon_machinegun",
|
||||
PlayerWeapon.Pickup_Weapon,
|
||||
PlayerWeapon.Use_Weapon,
|
||||
PlayerWeapon.Drop_Weapon,
|
||||
PlayerWeapon.Weapon_Machinegun,
|
||||
"misc/w_pkup.wav",
|
||||
"models/weapons/g_machn/tris.md2",
|
||||
Defines.EF_ROTATE,
|
||||
"models/weapons/v_machn/tris.md2",
|
||||
/* icon */
|
||||
"w_machinegun",
|
||||
/* pickup */
|
||||
"Machinegun",
|
||||
0,
|
||||
1,
|
||||
"Bullets",
|
||||
Defines.IT_WEAPON | Defines.IT_STAY_COOP,
|
||||
Defines.WEAP_MACHINEGUN,
|
||||
null,
|
||||
0,
|
||||
/* precache */
|
||||
"weapons/machgf1b.wav weapons/machgf2b.wav weapons/machgf3b.wav weapons/machgf4b.wav weapons/machgf5b.wav"),
|
||||
|
||||
/*
|
||||
* QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t(
|
||||
"weapon_chaingun",
|
||||
PlayerWeapon.Pickup_Weapon,
|
||||
PlayerWeapon.Use_Weapon,
|
||||
PlayerWeapon.Drop_Weapon,
|
||||
PlayerWeapon.Weapon_Chaingun,
|
||||
"misc/w_pkup.wav",
|
||||
"models/weapons/g_chain/tris.md2",
|
||||
Defines.EF_ROTATE,
|
||||
"models/weapons/v_chain/tris.md2",
|
||||
/* icon */
|
||||
"w_chaingun",
|
||||
/* pickup */
|
||||
"Chaingun",
|
||||
0,
|
||||
1,
|
||||
"Bullets",
|
||||
Defines.IT_WEAPON | Defines.IT_STAY_COOP,
|
||||
Defines.WEAP_CHAINGUN,
|
||||
null,
|
||||
0,
|
||||
/* precache */
|
||||
"weapons/chngnu1a.wav weapons/chngnl1a.wav weapons/machgf3b.wav` weapons/chngnd1a.wav"),
|
||||
|
||||
/*
|
||||
* QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t(
|
||||
"ammo_grenades",
|
||||
GameItems.Pickup_Ammo,
|
||||
PlayerWeapon.Use_Weapon,
|
||||
GameItems.Drop_Ammo,
|
||||
PlayerWeapon.Weapon_Grenade,
|
||||
"misc/am_pkup.wav",
|
||||
"models/items/ammo/grenades/medium/tris.md2",
|
||||
0,
|
||||
"models/weapons/v_handgr/tris.md2",
|
||||
/* icon */
|
||||
"a_grenades",
|
||||
/* pickup */
|
||||
"Grenades",
|
||||
/* width */
|
||||
3,
|
||||
5,
|
||||
"grenades",
|
||||
Defines.IT_AMMO | Defines.IT_WEAPON,
|
||||
Defines.WEAP_GRENADES,
|
||||
null,
|
||||
Defines.AMMO_GRENADES,
|
||||
/* precache */
|
||||
"weapons/hgrent1a.wav weapons/hgrena1b.wav weapons/hgrenc1b.wav weapons/hgrenb1a.wav weapons/hgrenb2a.wav "),
|
||||
|
||||
/*
|
||||
* QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t(
|
||||
"weapon_grenadelauncher",
|
||||
PlayerWeapon.Pickup_Weapon,
|
||||
PlayerWeapon.Use_Weapon,
|
||||
PlayerWeapon.Drop_Weapon,
|
||||
PlayerWeapon.Weapon_GrenadeLauncher,
|
||||
"misc/w_pkup.wav",
|
||||
"models/weapons/g_launch/tris.md2",
|
||||
Defines.EF_ROTATE,
|
||||
"models/weapons/v_launch/tris.md2",
|
||||
/* icon */
|
||||
"w_glauncher",
|
||||
/* pickup */
|
||||
"Grenade Launcher",
|
||||
0,
|
||||
1,
|
||||
"Grenades",
|
||||
Defines.IT_WEAPON | Defines.IT_STAY_COOP,
|
||||
Defines.WEAP_GRENADELAUNCHER,
|
||||
null,
|
||||
0,
|
||||
/* precache */
|
||||
"models/objects/grenade/tris.md2 weapons/grenlf1a.wav weapons/grenlr1b.wav weapons/grenlb1b.wav"),
|
||||
|
||||
/*
|
||||
* QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t(
|
||||
"weapon_rocketlauncher",
|
||||
PlayerWeapon.Pickup_Weapon,
|
||||
PlayerWeapon.Use_Weapon,
|
||||
PlayerWeapon.Drop_Weapon,
|
||||
PlayerWeapon.Weapon_RocketLauncher,
|
||||
"misc/w_pkup.wav",
|
||||
"models/weapons/g_rocket/tris.md2",
|
||||
Defines.EF_ROTATE,
|
||||
"models/weapons/v_rocket/tris.md2",
|
||||
/* icon */
|
||||
"w_rlauncher",
|
||||
/* pickup */
|
||||
"Rocket Launcher",
|
||||
0,
|
||||
1,
|
||||
"Rockets",
|
||||
Defines.IT_WEAPON | Defines.IT_STAY_COOP,
|
||||
Defines.WEAP_ROCKETLAUNCHER,
|
||||
null,
|
||||
0,
|
||||
/* precache */
|
||||
"models/objects/rocket/tris.md2 weapons/rockfly.wav weapons/rocklf1a.wav weapons/rocklr1b.wav models/objects/debris2/tris.md2"),
|
||||
|
||||
/*
|
||||
* QUAKED weapon_hyperblaster (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t(
|
||||
"weapon_hyperblaster",
|
||||
PlayerWeapon.Pickup_Weapon,
|
||||
PlayerWeapon.Use_Weapon,
|
||||
PlayerWeapon.Drop_Weapon,
|
||||
PlayerWeapon.Weapon_HyperBlaster,
|
||||
"misc/w_pkup.wav",
|
||||
"models/weapons/g_hyperb/tris.md2",
|
||||
Defines.EF_ROTATE,
|
||||
"models/weapons/v_hyperb/tris.md2",
|
||||
/* icon */
|
||||
"w_hyperblaster",
|
||||
/* pickup */
|
||||
"HyperBlaster",
|
||||
0,
|
||||
1,
|
||||
"Cells",
|
||||
Defines.IT_WEAPON | Defines.IT_STAY_COOP,
|
||||
Defines.WEAP_HYPERBLASTER,
|
||||
null,
|
||||
0,
|
||||
/* precache */
|
||||
"weapons/hyprbu1a.wav weapons/hyprbl1a.wav weapons/hyprbf1a.wav weapons/hyprbd1a.wav misc/lasfly.wav"),
|
||||
|
||||
/*
|
||||
* QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("weapon_railgun", PlayerWeapon.Pickup_Weapon,
|
||||
PlayerWeapon.Use_Weapon, PlayerWeapon.Drop_Weapon,
|
||||
PlayerWeapon.Weapon_Railgun, "misc/w_pkup.wav",
|
||||
"models/weapons/g_rail/tris.md2", Defines.EF_ROTATE,
|
||||
"models/weapons/v_rail/tris.md2",
|
||||
/* icon */
|
||||
"w_railgun",
|
||||
/* pickup */
|
||||
"Railgun", 0, 1, "Slugs", Defines.IT_WEAPON
|
||||
| Defines.IT_STAY_COOP, Defines.WEAP_RAILGUN, null,
|
||||
0,
|
||||
/* precache */
|
||||
"weapons/rg_hum.wav"),
|
||||
|
||||
/*
|
||||
* QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t(
|
||||
"weapon_bfg",
|
||||
PlayerWeapon.Pickup_Weapon,
|
||||
PlayerWeapon.Use_Weapon,
|
||||
PlayerWeapon.Drop_Weapon,
|
||||
PlayerWeapon.Weapon_BFG,
|
||||
"misc/w_pkup.wav",
|
||||
"models/weapons/g_bfg/tris.md2",
|
||||
Defines.EF_ROTATE,
|
||||
"models/weapons/v_bfg/tris.md2",
|
||||
/* icon */
|
||||
"w_bfg",
|
||||
/* pickup */
|
||||
"BFG10K",
|
||||
0,
|
||||
50,
|
||||
"Cells",
|
||||
Defines.IT_WEAPON | Defines.IT_STAY_COOP,
|
||||
Defines.WEAP_BFG,
|
||||
null,
|
||||
0,
|
||||
/* precache */
|
||||
"sprites/s_bfg1.sp2 sprites/s_bfg2.sp2 sprites/s_bfg3.sp2 weapons/bfg__f1y.wav weapons/bfg__l1a.wav weapons/bfg__x1b.wav weapons/bfg_hum.wav"),
|
||||
|
||||
//
|
||||
// AMMO ITEMS
|
||||
//
|
||||
|
||||
/*
|
||||
* QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("ammo_shells", GameItems.Pickup_Ammo, null, GameItems.Drop_Ammo, null,
|
||||
"misc/am_pkup.wav",
|
||||
"models/items/ammo/shells/medium/tris.md2", 0, null,
|
||||
/* icon */
|
||||
"a_shells",
|
||||
/* pickup */
|
||||
"Shells",
|
||||
/* width */
|
||||
3, 10, null, Defines.IT_AMMO, 0, null, Defines.AMMO_SHELLS,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("ammo_bullets", GameItems.Pickup_Ammo, null, GameItems.Drop_Ammo, null,
|
||||
"misc/am_pkup.wav",
|
||||
"models/items/ammo/bullets/medium/tris.md2", 0, null,
|
||||
/* icon */
|
||||
"a_bullets",
|
||||
/* pickup */
|
||||
"Bullets",
|
||||
/* width */
|
||||
3, 50, null, Defines.IT_AMMO, 0, null,
|
||||
Defines.AMMO_BULLETS,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("ammo_cells", GameItems.Pickup_Ammo, null, GameItems.Drop_Ammo, null,
|
||||
"misc/am_pkup.wav",
|
||||
"models/items/ammo/cells/medium/tris.md2", 0, null,
|
||||
/* icon */
|
||||
"a_cells",
|
||||
/* pickup */
|
||||
"Cells",
|
||||
/* width */
|
||||
3, 50, null, Defines.IT_AMMO, 0, null, Defines.AMMO_CELLS,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("ammo_rockets", GameItems.Pickup_Ammo, null, GameItems.Drop_Ammo, null,
|
||||
"misc/am_pkup.wav",
|
||||
"models/items/ammo/rockets/medium/tris.md2", 0, null,
|
||||
/* icon */
|
||||
"a_rockets",
|
||||
/* pickup */
|
||||
"Rockets",
|
||||
/* width */
|
||||
3, 5, null, Defines.IT_AMMO, 0, null, Defines.AMMO_ROCKETS,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("ammo_slugs", GameItems.Pickup_Ammo, null, GameItems.Drop_Ammo, null,
|
||||
"misc/am_pkup.wav",
|
||||
"models/items/ammo/slugs/medium/tris.md2", 0, null,
|
||||
/* icon */
|
||||
"a_slugs",
|
||||
/* pickup */
|
||||
"Slugs",
|
||||
/* width */
|
||||
3, 10, null, Defines.IT_AMMO, 0, null, Defines.AMMO_SLUGS,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
//
|
||||
// POWERUP ITEMS
|
||||
//
|
||||
/*
|
||||
* QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("item_quad", GameItems.Pickup_Powerup, GameItems.Use_Quad,
|
||||
GameItems.Drop_General, null, "items/pkup.wav",
|
||||
"models/items/quaddama/tris.md2", Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"p_quad",
|
||||
/* pickup */
|
||||
"Quad Damage",
|
||||
/* width */
|
||||
2, 60, null, Defines.IT_POWERUP, 0, null, 0,
|
||||
/* precache */
|
||||
"items/damage.wav items/damage2.wav items/damage3.wav"),
|
||||
|
||||
/*
|
||||
* QUAKED item_invulnerability (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("item_invulnerability", GameItems.Pickup_Powerup,
|
||||
GameItems.Use_Invulnerability, GameItems.Drop_General, null,
|
||||
"items/pkup.wav", "models/items/invulner/tris.md2",
|
||||
Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"p_invulnerability",
|
||||
/* pickup */
|
||||
"Invulnerability",
|
||||
/* width */
|
||||
2, 300, null, Defines.IT_POWERUP, 0, null, 0,
|
||||
/* precache */
|
||||
"items/protect.wav items/protect2.wav items/protect4.wav"),
|
||||
|
||||
/*
|
||||
* QUAKED item_silencer (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("item_silencer", GameItems.Pickup_Powerup, GameItems.Use_Silencer,
|
||||
GameItems.Drop_General, null, "items/pkup.wav",
|
||||
"models/items/silencer/tris.md2", Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"p_silencer",
|
||||
/* pickup */
|
||||
"Silencer",
|
||||
/* width */
|
||||
2, 60, null, Defines.IT_POWERUP, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED item_breather (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("item_breather", GameItems.Pickup_Powerup, GameItems.Use_Breather,
|
||||
GameItems.Drop_General, null, "items/pkup.wav",
|
||||
"models/items/breather/tris.md2", Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"p_rebreather",
|
||||
/* pickup */
|
||||
"Rebreather",
|
||||
/* width */
|
||||
2, 60, null, Defines.IT_STAY_COOP | Defines.IT_POWERUP, 0,
|
||||
null, 0,
|
||||
/* precache */
|
||||
"items/airout.wav"),
|
||||
|
||||
/*
|
||||
* QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("item_enviro", GameItems.Pickup_Powerup, GameItems.Use_Envirosuit,
|
||||
GameItems.Drop_General, null, "items/pkup.wav",
|
||||
"models/items/enviro/tris.md2", Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"p_envirosuit",
|
||||
/* pickup */
|
||||
"Environment Suit",
|
||||
/* width */
|
||||
2, 60, null, Defines.IT_STAY_COOP | Defines.IT_POWERUP, 0,
|
||||
null, 0,
|
||||
/* precache */
|
||||
"items/airout.wav"),
|
||||
|
||||
/*
|
||||
* QUAKED item_ancient_head (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
* Special item that gives +2 to maximum health
|
||||
*/
|
||||
new gitem_t("item_ancient_head", GameItems.Pickup_AncientHead, null, null,
|
||||
null, "items/pkup.wav", "models/items/c_head/tris.md2",
|
||||
Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"i_fixme",
|
||||
/* pickup */
|
||||
"Ancient Head",
|
||||
/* width */
|
||||
2, 60, null, 0, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED item_adrenaline (.3 .3 1) (-16 -16 -16) (16 16 16) gives
|
||||
* +1 to maximum health
|
||||
*/
|
||||
new gitem_t("item_adrenaline", GameItems.Pickup_Adrenaline, null, null, null,
|
||||
"items/pkup.wav", "models/items/adrenal/tris.md2",
|
||||
Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"p_adrenaline",
|
||||
/* pickup */
|
||||
"Adrenaline",
|
||||
/* width */
|
||||
2, 60, null, 0, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED item_bandolier (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("item_bandolier", GameItems.Pickup_Bandolier, null, null, null,
|
||||
"items/pkup.wav", "models/items/band/tris.md2",
|
||||
Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"p_bandolier",
|
||||
/* pickup */
|
||||
"Bandolier",
|
||||
/* width */
|
||||
2, 60, null, 0, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED item_pack (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
*/
|
||||
new gitem_t("item_pack", GameItems.Pickup_Pack, null, null, null,
|
||||
"items/pkup.wav", "models/items/pack/tris.md2",
|
||||
Defines.EF_ROTATE, null,
|
||||
/* icon */
|
||||
"i_pack",
|
||||
/* pickup */
|
||||
"Ammo Pack",
|
||||
/* width */
|
||||
2, 180, null, 0, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
//
|
||||
// KEYS
|
||||
//
|
||||
/*
|
||||
* QUAKED key_data_cd (0 .5 .8) (-16 -16 -16) (16 16 16) key for
|
||||
* computer centers
|
||||
*/
|
||||
new gitem_t("key_data_cd", GameItems.Pickup_Key, null, GameItems.Drop_General,
|
||||
null, "items/pkup.wav",
|
||||
"models/items/keys/data_cd/tris.md2", Defines.EF_ROTATE,
|
||||
null, "k_datacd", "Data CD", 2, 0, null,
|
||||
Defines.IT_STAY_COOP | Defines.IT_KEY, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED key_power_cube (0 .5 .8) (-16 -16 -16) (16 16 16)
|
||||
* TRIGGER_SPAWN NO_TOUCH warehouse circuits
|
||||
*/
|
||||
new gitem_t("key_power_cube", GameItems.Pickup_Key, null,
|
||||
GameItems.Drop_General, null, "items/pkup.wav",
|
||||
"models/items/keys/power/tris.md2", Defines.EF_ROTATE,
|
||||
null, "k_powercube", "Power Cube", 2, 0, null,
|
||||
Defines.IT_STAY_COOP | Defines.IT_KEY, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED key_pyramid (0 .5 .8) (-16 -16 -16) (16 16 16) key for the
|
||||
* entrance of jail3
|
||||
*/
|
||||
new gitem_t("key_pyramid", GameItems.Pickup_Key, null, GameItems.Drop_General,
|
||||
null, "items/pkup.wav",
|
||||
"models/items/keys/pyramid/tris.md2", Defines.EF_ROTATE,
|
||||
null, "k_pyramid", "Pyramid Key", 2, 0, null,
|
||||
Defines.IT_STAY_COOP | Defines.IT_KEY, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED key_data_spinner (0 .5 .8) (-16 -16 -16) (16 16 16) key
|
||||
* for the city computer
|
||||
*/
|
||||
new gitem_t("key_data_spinner", GameItems.Pickup_Key, null,
|
||||
GameItems.Drop_General, null, "items/pkup.wav",
|
||||
"models/items/keys/spinner/tris.md2", Defines.EF_ROTATE,
|
||||
null, "k_dataspin", "Data Spinner", 2, 0, null,
|
||||
Defines.IT_STAY_COOP | Defines.IT_KEY, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED key_pass (0 .5 .8) (-16 -16 -16) (16 16 16) security pass
|
||||
* for the security level
|
||||
*/
|
||||
new gitem_t("key_pass", GameItems.Pickup_Key, null, GameItems.Drop_General,
|
||||
null, "items/pkup.wav", "models/items/keys/pass/tris.md2",
|
||||
Defines.EF_ROTATE, null, "k_security", "Security Pass", 2,
|
||||
0, null, Defines.IT_STAY_COOP | Defines.IT_KEY, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED key_blue_key (0 .5 .8) (-16 -16 -16) (16 16 16) normal
|
||||
* door key - blue
|
||||
*/
|
||||
new gitem_t("key_blue_key", GameItems.Pickup_Key, null,
|
||||
GameItems.Drop_General, null, "items/pkup.wav",
|
||||
"models/items/keys/key/tris.md2", Defines.EF_ROTATE, null,
|
||||
"k_bluekey", "Blue Key", 2, 0, null, Defines.IT_STAY_COOP
|
||||
| Defines.IT_KEY, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED key_red_key (0 .5 .8) (-16 -16 -16) (16 16 16) normal door
|
||||
* key - red
|
||||
*/
|
||||
new gitem_t("key_red_key", GameItems.Pickup_Key, null, GameItems.Drop_General,
|
||||
null, "items/pkup.wav",
|
||||
"models/items/keys/red_key/tris.md2", Defines.EF_ROTATE,
|
||||
null, "k_redkey", "Red Key", 2, 0, null,
|
||||
Defines.IT_STAY_COOP | Defines.IT_KEY, 0, null, 0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED key_commander_head (0 .5 .8) (-16 -16 -16) (16 16 16) tank
|
||||
* commander's head
|
||||
*/
|
||||
new gitem_t("key_commander_head", GameItems.Pickup_Key, null,
|
||||
GameItems.Drop_General, null, "items/pkup.wav",
|
||||
"models/monsters/commandr/head/tris.md2", Defines.EF_GIB,
|
||||
null,
|
||||
/* icon */
|
||||
"k_comhead",
|
||||
/* pickup */
|
||||
"Commander's Head",
|
||||
/* width */
|
||||
2, 0, null, Defines.IT_STAY_COOP | Defines.IT_KEY, 0, null,
|
||||
0,
|
||||
/* precache */
|
||||
""),
|
||||
|
||||
/*
|
||||
* QUAKED key_airstrike_target (0 .5 .8) (-16 -16 -16) (16 16 16)
|
||||
* tank commander's head
|
||||
*/
|
||||
new gitem_t("key_airstrike_target", GameItems.Pickup_Key, null,
|
||||
GameItems.Drop_General, null, "items/pkup.wav",
|
||||
"models/items/keys/target/tris.md2", Defines.EF_ROTATE,
|
||||
null,
|
||||
/* icon */
|
||||
"i_airstrike",
|
||||
/* pickup */
|
||||
"Airstrike Marker",
|
||||
/* width */
|
||||
2, 0, null, Defines.IT_STAY_COOP | Defines.IT_KEY, 0, null,
|
||||
0,
|
||||
/* precache */
|
||||
""),
|
||||
new gitem_t(null, GameItems.Pickup_Health, null, null, null,
|
||||
"items/pkup.wav", null, 0, null,
|
||||
/* icon */
|
||||
"i_health",
|
||||
/* pickup */
|
||||
"Health",
|
||||
/* width */
|
||||
3, 0, null, 0, 0, null, 0,
|
||||
/* precache */
|
||||
"items/s_health.wav items/n_health.wav items/l_health.wav items/m_health.wav"),
|
||||
|
||||
// end of list marker
|
||||
null };
|
||||
}
|
||||
1351
src/main/java/lwjake2/game/GameItems.java
Normal file
1351
src/main/java/lwjake2/game/GameItems.java
Normal file
File diff suppressed because it is too large
Load Diff
1943
src/main/java/lwjake2/game/GameMisc.java
Normal file
1943
src/main/java/lwjake2/game/GameMisc.java
Normal file
File diff suppressed because it is too large
Load Diff
294
src/main/java/lwjake2/game/GameSVCmds.java
Normal file
294
src/main/java/lwjake2/game/GameSVCmds.java
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.util.Lib;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class GameSVCmds {
|
||||
|
||||
/**
|
||||
*
|
||||
* PACKET FILTERING
|
||||
*
|
||||
*
|
||||
* You can add or remove addresses from the filter list with:
|
||||
*
|
||||
* addip <ip> removeip <ip>
|
||||
*
|
||||
* The ip address is specified in dot format, and any unspecified digits
|
||||
* will match any value, so you can specify an entire class C network with
|
||||
* "addip 192.246.40".
|
||||
*
|
||||
* Removeip will only remove an address specified exactly the same way. You
|
||||
* cannot addip a subnet, then removeip a single host.
|
||||
*
|
||||
* listip Prints the current list of filters.
|
||||
*
|
||||
* writeip Dumps "addip <ip>" commands to listip.cfg so it can be execed at
|
||||
* a later date. The filter lists are not saved and restored by default,
|
||||
* because I beleive it would cause too much confusion.
|
||||
*
|
||||
* filterban <0 or 1>
|
||||
*
|
||||
* If 1 (the default), then ip addresses matching the current list will be
|
||||
* prohibited from entering the game. This is the default setting.
|
||||
*
|
||||
* If 0, then only addresses matching the list will be allowed. This lets
|
||||
* you easily set up a private game, or a game that only allows players from
|
||||
* your local network.
|
||||
*
|
||||
*/
|
||||
|
||||
public static class ipfilter_t {
|
||||
int mask;
|
||||
|
||||
int compare;
|
||||
};
|
||||
|
||||
public static void Svcmd_Test_f() {
|
||||
GameBase.gi.cprintf(null, Defines.PRINT_HIGH, "Svcmd_Test_f()\n");
|
||||
}
|
||||
|
||||
public static final int MAX_IPFILTERS = 1024;
|
||||
|
||||
static GameSVCmds.ipfilter_t ipfilters[] = new GameSVCmds.ipfilter_t[MAX_IPFILTERS];
|
||||
|
||||
static int numipfilters;
|
||||
static {
|
||||
for (int n = 0; n < GameSVCmds.MAX_IPFILTERS; n++)
|
||||
GameSVCmds.ipfilters[n] = new ipfilter_t();
|
||||
}
|
||||
|
||||
/**
|
||||
* StringToFilter.
|
||||
*/
|
||||
static boolean StringToFilter(String s, GameSVCmds.ipfilter_t f) {
|
||||
|
||||
byte b[] = { 0, 0, 0, 0 };
|
||||
byte m[] = { 0, 0, 0, 0 };
|
||||
|
||||
try {
|
||||
StringTokenizer tk = new StringTokenizer(s, ". ");
|
||||
|
||||
for (int n = 0; n < 4; n++) {
|
||||
b[n] = (byte) Lib.atoi(tk.nextToken());
|
||||
if (b[n] != 0)
|
||||
m[n] = -1;
|
||||
}
|
||||
|
||||
f.mask = ByteBuffer.wrap(m).getInt();
|
||||
f.compare = ByteBuffer.wrap(b).getInt();
|
||||
} catch (Exception e) {
|
||||
GameBase.gi.cprintf(null, Defines.PRINT_HIGH,
|
||||
"Bad filter address: " + s + "\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* SV_FilterPacket.
|
||||
*/
|
||||
static boolean SV_FilterPacket(String from) {
|
||||
int i;
|
||||
int in;
|
||||
int m[] = { 0, 0, 0, 0 };
|
||||
|
||||
int p = 0;
|
||||
char c;
|
||||
|
||||
i = 0;
|
||||
|
||||
while (p < from.length() && i < 4) {
|
||||
m[i] = 0;
|
||||
|
||||
c = from.charAt(p);
|
||||
while (c >= '0' && c <= '9') {
|
||||
m[i] = m[i] * 10 + (c - '0');
|
||||
c = from.charAt(p++);
|
||||
}
|
||||
if (p == from.length() || c == ':')
|
||||
break;
|
||||
|
||||
i++;
|
||||
p++;
|
||||
}
|
||||
|
||||
in = (m[0] & 0xff) | ((m[1] & 0xff) << 8) | ((m[2] & 0xff) << 16)
|
||||
| ((m[3] & 0xff) << 24);
|
||||
|
||||
for (i = 0; i < numipfilters; i++)
|
||||
if ((in & ipfilters[i].mask) == ipfilters[i].compare)
|
||||
return ((int) GameBase.filterban.value) != 0;
|
||||
|
||||
return ((int) 1 - GameBase.filterban.value) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* SV_AddIP_f.
|
||||
*/
|
||||
static void SVCmd_AddIP_f() {
|
||||
int i;
|
||||
|
||||
if (GameBase.gi.argc() < 3) {
|
||||
GameBase.gi.cprintf(null, Defines.PRINT_HIGH,
|
||||
"Usage: addip <ip-mask>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < numipfilters; i++)
|
||||
if (ipfilters[i].compare == 0xffffffff)
|
||||
break; // free spot
|
||||
if (i == numipfilters) {
|
||||
if (numipfilters == MAX_IPFILTERS) {
|
||||
GameBase.gi.cprintf(null, Defines.PRINT_HIGH,
|
||||
"IP filter list is full\n");
|
||||
return;
|
||||
}
|
||||
numipfilters++;
|
||||
}
|
||||
|
||||
if (!StringToFilter(GameBase.gi.argv(2), ipfilters[i]))
|
||||
ipfilters[i].compare = 0xffffffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* SV_RemoveIP_f.
|
||||
*/
|
||||
static void SVCmd_RemoveIP_f() {
|
||||
GameSVCmds.ipfilter_t f = new GameSVCmds.ipfilter_t();
|
||||
int i, j;
|
||||
|
||||
if (GameBase.gi.argc() < 3) {
|
||||
GameBase.gi.cprintf(null, Defines.PRINT_HIGH,
|
||||
"Usage: sv removeip <ip-mask>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!StringToFilter(GameBase.gi.argv(2), f))
|
||||
return;
|
||||
|
||||
for (i = 0; i < numipfilters; i++)
|
||||
if (ipfilters[i].mask == f.mask
|
||||
&& ipfilters[i].compare == f.compare) {
|
||||
for (j = i + 1; j < numipfilters; j++)
|
||||
ipfilters[j - 1] = ipfilters[j];
|
||||
numipfilters--;
|
||||
GameBase.gi.cprintf(null, Defines.PRINT_HIGH, "Removed.\n");
|
||||
return;
|
||||
}
|
||||
GameBase.gi.cprintf(null, Defines.PRINT_HIGH, "Didn't find "
|
||||
+ GameBase.gi.argv(2) + ".\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* SV_ListIP_f.
|
||||
*/
|
||||
static void SVCmd_ListIP_f() {
|
||||
int i;
|
||||
byte b[];
|
||||
|
||||
GameBase.gi.cprintf(null, Defines.PRINT_HIGH, "Filter list:\n");
|
||||
for (i = 0; i < numipfilters; i++) {
|
||||
b = Lib.getIntBytes(ipfilters[i].compare);
|
||||
GameBase.gi
|
||||
.cprintf(null, Defines.PRINT_HIGH, (b[0] & 0xff) + "."
|
||||
+ (b[1] & 0xff) + "." + (b[2] & 0xff) + "."
|
||||
+ (b[3] & 0xff));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SV_WriteIP_f.
|
||||
*/
|
||||
static void SVCmd_WriteIP_f() {
|
||||
RandomAccessFile f;
|
||||
//char name[MAX_OSPATH];
|
||||
String name;
|
||||
byte b[];
|
||||
|
||||
int i;
|
||||
cvar_t game;
|
||||
|
||||
game = GameBase.gi.cvar("game", "", 0);
|
||||
|
||||
if (game.string == null)
|
||||
name = Defines.GAMEVERSION + "/listip.cfg";
|
||||
else
|
||||
name = game.string + "/listip.cfg";
|
||||
|
||||
GameBase.gi.cprintf(null, Defines.PRINT_HIGH, "Writing " + name + ".\n");
|
||||
|
||||
f = Lib.fopen(name, "rw");
|
||||
if (f == null) {
|
||||
GameBase.gi.cprintf(null, Defines.PRINT_HIGH, "Couldn't open "
|
||||
+ name + "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
f.writeChars("set filterban " + (int) GameBase.filterban.value
|
||||
+ "\n");
|
||||
|
||||
for (i = 0; i < numipfilters; i++) {
|
||||
b = Lib.getIntBytes(ipfilters[i].compare);
|
||||
f.writeChars("sv addip " + (b[0] & 0xff) + "." + (b[1] & 0xff)
|
||||
+ "." + (b[2] & 0xff) + "." + (b[3] & 0xff) + "\n");
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
Com.Printf("IOError in SVCmd_WriteIP_f:" + e);
|
||||
}
|
||||
|
||||
Lib.fclose(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* ServerCommand
|
||||
*
|
||||
* ServerCommand will be called when an "sv" command is issued. The game can
|
||||
* issue gi.argc() / gi.argv() commands to get the rest of the parameters
|
||||
*/
|
||||
public static void ServerCommand() {
|
||||
String cmd;
|
||||
|
||||
cmd = GameBase.gi.argv(1);
|
||||
if (Lib.Q_stricmp(cmd, "test") == 0)
|
||||
Svcmd_Test_f();
|
||||
else if (Lib.Q_stricmp(cmd, "addip") == 0)
|
||||
SVCmd_AddIP_f();
|
||||
else if (Lib.Q_stricmp(cmd, "removeip") == 0)
|
||||
SVCmd_RemoveIP_f();
|
||||
else if (Lib.Q_stricmp(cmd, "listip") == 0)
|
||||
SVCmd_ListIP_f();
|
||||
else if (Lib.Q_stricmp(cmd, "writeip") == 0)
|
||||
SVCmd_WriteIP_f();
|
||||
else
|
||||
GameBase.gi.cprintf(null, Defines.PRINT_HIGH,
|
||||
"Unknown server command \"" + cmd + "\"\n");
|
||||
}
|
||||
}
|
||||
377
src/main/java/lwjake2/game/GameSave.java
Normal file
377
src/main/java/lwjake2/game/GameSave.java
Normal file
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.QuakeFile;
|
||||
|
||||
@Slf4j
|
||||
public class GameSave {
|
||||
public static void CreateEdicts() {
|
||||
GameBase.g_edicts = new edict_t[GameBase.game.maxentities];
|
||||
for (int i = 0; i < GameBase.game.maxentities; i++)
|
||||
GameBase.g_edicts[i] = new edict_t(i);
|
||||
}
|
||||
|
||||
public static void CreateClients() {
|
||||
GameBase.game.clients = new gclient_t[GameBase.game.maxclients];
|
||||
for (int i = 0; i < GameBase.game.maxclients; i++)
|
||||
GameBase.game.clients[i] = new gclient_t(i);
|
||||
|
||||
}
|
||||
|
||||
private static String preloadclasslist [] =
|
||||
{
|
||||
"jake2.game.PlayerWeapon",
|
||||
"jake2.game.AIAdapter",
|
||||
"jake2.game.Cmd",
|
||||
"jake2.game.EdictFindFilter",
|
||||
"jake2.game.EdictIterator",
|
||||
"jake2.game.EndianHandler",
|
||||
"jake2.game.EntBlockedAdapter",
|
||||
"jake2.game.EntDieAdapter",
|
||||
"jake2.game.EntDodgeAdapter",
|
||||
"jake2.game.EntInteractAdapter",
|
||||
"jake2.game.EntPainAdapter",
|
||||
"jake2.game.EntThinkAdapter",
|
||||
"jake2.game.EntTouchAdapter",
|
||||
"jake2.game.EntUseAdapter",
|
||||
"jake2.game.GameAI",
|
||||
"jake2.game.GameBase",
|
||||
"jake2.game.GameChase",
|
||||
"jake2.game.GameCombat",
|
||||
"jake2.game.GameFunc",
|
||||
"jake2.game.GameMisc",
|
||||
"jake2.game.GameSVCmds",
|
||||
"jake2.game.GameSave",
|
||||
"jake2.game.GameSpawn",
|
||||
"jake2.game.GameTarget",
|
||||
"jake2.game.GameTrigger",
|
||||
"jake2.game.GameTurret",
|
||||
"jake2.game.GameUtil",
|
||||
"jake2.game.GameWeapon",
|
||||
"jake2.game.Info",
|
||||
"jake2.game.ItemDropAdapter",
|
||||
"jake2.game.ItemUseAdapter",
|
||||
"jake2.game.Monster",
|
||||
"jake2.game.PlayerClient",
|
||||
"jake2.game.PlayerHud",
|
||||
"jake2.game.PlayerTrail",
|
||||
"jake2.game.PlayerView",
|
||||
"jake2.game.SuperAdapter",
|
||||
"jake2.game.monsters.M_Actor",
|
||||
"jake2.game.monsters.M_Berserk",
|
||||
"jake2.game.monsters.M_Boss2",
|
||||
"jake2.game.monsters.M_Boss3",
|
||||
"jake2.game.monsters.M_Boss31",
|
||||
"jake2.game.monsters.M_Boss32",
|
||||
"jake2.game.monsters.M_Brain",
|
||||
"jake2.game.monsters.M_Chick",
|
||||
"jake2.game.monsters.M_Flash",
|
||||
"jake2.game.monsters.M_Flipper",
|
||||
"jake2.game.monsters.M_Float",
|
||||
"jake2.game.monsters.M_Flyer",
|
||||
"jake2.game.monsters.M_Gladiator",
|
||||
"jake2.game.monsters.M_Gunner",
|
||||
"jake2.game.monsters.M_Hover",
|
||||
"jake2.game.monsters.M_Infantry",
|
||||
"jake2.game.monsters.M_Insane",
|
||||
"jake2.game.monsters.M_Medic",
|
||||
"jake2.game.monsters.M_Mutant",
|
||||
"jake2.game.monsters.M_Parasite",
|
||||
"jake2.game.monsters.M_Player",
|
||||
"jake2.game.monsters.M_Soldier",
|
||||
"jake2.game.monsters.M_Supertank",
|
||||
"jake2.game.monsters.M_Tank",
|
||||
"jake2.game.GameItems",
|
||||
// DANGER! init as last, when all adatpers are != null
|
||||
"jake2.game.GameItemList"
|
||||
};
|
||||
|
||||
/**
|
||||
* InitGame
|
||||
*
|
||||
* This will be called when the dll is first loaded, which only happens when
|
||||
* a new game is started or a save game is loaded.
|
||||
*/
|
||||
public static void InitGame() {
|
||||
log.info("==== InitGame ====");
|
||||
|
||||
// preload all classes to register the adapters
|
||||
for ( int n=0; n < preloadclasslist.length; n++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class.forName(preloadclasslist[n]);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Com.DPrintf("error loading class: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GameBase.gun_x = GameBase.gi.cvar("gun_x", "0", 0);
|
||||
GameBase.gun_y = GameBase.gi.cvar("gun_y", "0", 0);
|
||||
GameBase.gun_z = GameBase.gi.cvar("gun_z", "0", 0);
|
||||
|
||||
//FIXME: sv_ prefix are wrong names for these variables
|
||||
GameBase.sv_rollspeed = GameBase.gi.cvar("sv_rollspeed", "200", 0);
|
||||
GameBase.sv_rollangle = GameBase.gi.cvar("sv_rollangle", "2", 0);
|
||||
GameBase.sv_maxvelocity = GameBase.gi.cvar("sv_maxvelocity", "2000", 0);
|
||||
GameBase.sv_gravity = GameBase.gi.cvar("sv_gravity", "800", 0);
|
||||
|
||||
// noset vars
|
||||
Globals.dedicated = GameBase.gi.cvar("dedicated", "0",
|
||||
Defines.CVAR_NOSET);
|
||||
|
||||
// latched vars
|
||||
GameBase.sv_cheats = GameBase.gi.cvar("cheats", "0",
|
||||
Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH);
|
||||
GameBase.gi.cvar("gamename", Defines.GAMEVERSION,
|
||||
Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH);
|
||||
GameBase.gi.cvar("gamedate", Globals.__DATE__, Defines.CVAR_SERVERINFO
|
||||
| Defines.CVAR_LATCH);
|
||||
|
||||
GameBase.maxclients = GameBase.gi.cvar("maxclients", "4",
|
||||
Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH);
|
||||
GameBase.maxspectators = GameBase.gi.cvar("maxspectators", "4",
|
||||
Defines.CVAR_SERVERINFO);
|
||||
GameBase.deathmatch = GameBase.gi.cvar("deathmatch", "0",
|
||||
Defines.CVAR_LATCH);
|
||||
GameBase.coop = GameBase.gi.cvar("coop", "0", Defines.CVAR_LATCH);
|
||||
GameBase.skill = GameBase.gi.cvar("skill", "0", Defines.CVAR_LATCH);
|
||||
GameBase.maxentities = GameBase.gi.cvar("maxentities", "1024",
|
||||
Defines.CVAR_LATCH);
|
||||
|
||||
// change anytime vars
|
||||
GameBase.dmflags = GameBase.gi.cvar("dmflags", "0",
|
||||
Defines.CVAR_SERVERINFO);
|
||||
GameBase.fraglimit = GameBase.gi.cvar("fraglimit", "0",
|
||||
Defines.CVAR_SERVERINFO);
|
||||
GameBase.timelimit = GameBase.gi.cvar("timelimit", "0",
|
||||
Defines.CVAR_SERVERINFO);
|
||||
GameBase.password = GameBase.gi.cvar("password", "",
|
||||
Defines.CVAR_USERINFO);
|
||||
GameBase.spectator_password = GameBase.gi.cvar("spectator_password",
|
||||
"", Defines.CVAR_USERINFO);
|
||||
GameBase.needpass = GameBase.gi.cvar("needpass", "0",
|
||||
Defines.CVAR_SERVERINFO);
|
||||
GameBase.filterban = GameBase.gi.cvar("filterban", "1", 0);
|
||||
|
||||
GameBase.g_select_empty = GameBase.gi.cvar("g_select_empty", "0",
|
||||
Defines.CVAR_ARCHIVE);
|
||||
|
||||
GameBase.run_pitch = GameBase.gi.cvar("run_pitch", "0.002", 0);
|
||||
GameBase.run_roll = GameBase.gi.cvar("run_roll", "0.005", 0);
|
||||
GameBase.bob_up = GameBase.gi.cvar("bob_up", "0.005", 0);
|
||||
GameBase.bob_pitch = GameBase.gi.cvar("bob_pitch", "0.002", 0);
|
||||
GameBase.bob_roll = GameBase.gi.cvar("bob_roll", "0.002", 0);
|
||||
|
||||
// flood control
|
||||
GameBase.flood_msgs = GameBase.gi.cvar("flood_msgs", "4", 0);
|
||||
GameBase.flood_persecond = GameBase.gi.cvar("flood_persecond", "4", 0);
|
||||
GameBase.flood_waitdelay = GameBase.gi.cvar("flood_waitdelay", "10", 0);
|
||||
|
||||
// dm map list
|
||||
GameBase.sv_maplist = GameBase.gi.cvar("sv_maplist", "", 0);
|
||||
|
||||
// items
|
||||
GameItems.InitItems();
|
||||
|
||||
GameBase.game.helpmessage1 = "";
|
||||
GameBase.game.helpmessage2 = "";
|
||||
|
||||
// initialize all entities for this game
|
||||
GameBase.game.maxentities = (int) GameBase.maxentities.value;
|
||||
CreateEdicts();
|
||||
|
||||
// initialize all clients for this game
|
||||
GameBase.game.maxclients = (int) GameBase.maxclients.value;
|
||||
|
||||
CreateClients();
|
||||
|
||||
GameBase.num_edicts = GameBase.game.maxclients + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* WriteGame
|
||||
*
|
||||
* This will be called whenever the game goes to a new level, and when the
|
||||
* user explicitly saves the game.
|
||||
*
|
||||
* Game information include cross level data, like multi level triggers,
|
||||
* help computer info, and all client states.
|
||||
*
|
||||
* A single player death will automatically restore from the last save
|
||||
* position.
|
||||
*/
|
||||
public static void WriteGame(String filename, boolean autosave) {
|
||||
try {
|
||||
QuakeFile f;
|
||||
|
||||
if (!autosave)
|
||||
PlayerClient.SaveClientData();
|
||||
|
||||
f = new QuakeFile(filename, "rw");
|
||||
|
||||
GameBase.game.autosaved = autosave;
|
||||
GameBase.game.write(f);
|
||||
GameBase.game.autosaved = false;
|
||||
|
||||
for (int i = 0; i < GameBase.game.maxclients; i++)
|
||||
GameBase.game.clients[i].write(f);
|
||||
|
||||
Lib.fclose(f);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
GameBase.gi.error("Couldn't write to " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ReadGame(String filename) {
|
||||
|
||||
QuakeFile f = null;
|
||||
|
||||
try {
|
||||
|
||||
f = new QuakeFile(filename, "r");
|
||||
CreateEdicts();
|
||||
|
||||
GameBase.game.load(f);
|
||||
|
||||
for (int i = 0; i < GameBase.game.maxclients; i++) {
|
||||
GameBase.game.clients[i] = new gclient_t(i);
|
||||
GameBase.game.clients[i].read(f);
|
||||
}
|
||||
|
||||
f.close();
|
||||
}
|
||||
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WriteLevel
|
||||
*/
|
||||
public static void WriteLevel(String filename) {
|
||||
try {
|
||||
int i;
|
||||
edict_t ent;
|
||||
QuakeFile f;
|
||||
|
||||
f = new QuakeFile(filename, "rw");
|
||||
|
||||
// write out level_locals_t
|
||||
GameBase.level.write(f);
|
||||
|
||||
// write out all the entities
|
||||
for (i = 0; i < GameBase.num_edicts; i++) {
|
||||
ent = GameBase.g_edicts[i];
|
||||
if (!ent.inuse)
|
||||
continue;
|
||||
f.writeInt(i);
|
||||
ent.write(f);
|
||||
}
|
||||
|
||||
i = -1;
|
||||
f.writeInt(-1);
|
||||
|
||||
f.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
GameBase.gi.error("Couldn't open for writing: " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ReadLevel
|
||||
*
|
||||
* SpawnEntities will allready have been called on the level the same way it
|
||||
* was when the level was saved.
|
||||
*
|
||||
* That is necessary to get the baselines set up identically.
|
||||
*
|
||||
* The server will have cleared all of the world links before calling
|
||||
* ReadLevel.
|
||||
*
|
||||
* No clients are connected yet.
|
||||
*/
|
||||
public static void ReadLevel(String filename) {
|
||||
try {
|
||||
edict_t ent;
|
||||
|
||||
QuakeFile f = new QuakeFile(filename, "r");
|
||||
|
||||
// wipe all the entities
|
||||
CreateEdicts();
|
||||
|
||||
GameBase.num_edicts = (int) GameBase.maxclients.value + 1;
|
||||
|
||||
// load the level locals
|
||||
GameBase.level.read(f);
|
||||
|
||||
// load all the entities
|
||||
while (true) {
|
||||
int entnum = f.readInt();
|
||||
if (entnum == -1)
|
||||
break;
|
||||
|
||||
if (entnum >= GameBase.num_edicts)
|
||||
GameBase.num_edicts = entnum + 1;
|
||||
|
||||
ent = GameBase.g_edicts[entnum];
|
||||
ent.read(f);
|
||||
ent.cleararealinks();
|
||||
GameBase.gi.linkentity(ent);
|
||||
}
|
||||
|
||||
Lib.fclose(f);
|
||||
|
||||
// mark all clients as unconnected
|
||||
for (int i = 0; i < GameBase.maxclients.value; i++) {
|
||||
ent = GameBase.g_edicts[i + 1];
|
||||
ent.client = GameBase.game.clients[i];
|
||||
ent.client.pers.connected = false;
|
||||
}
|
||||
|
||||
// do any load time things at this point
|
||||
for (int i = 0; i < GameBase.num_edicts; i++) {
|
||||
ent = GameBase.g_edicts[i];
|
||||
|
||||
if (!ent.inuse)
|
||||
continue;
|
||||
|
||||
// fire any cross-level triggers
|
||||
if (ent.classname != null)
|
||||
if (Lib.strcmp(ent.classname, "target_crosslevel_target") == 0)
|
||||
ent.nextthink = GameBase.level.time + ent.delay;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
GameBase.gi.error("Couldn't read level file " + filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
1214
src/main/java/lwjake2/game/GameSpawn.java
Normal file
1214
src/main/java/lwjake2/game/GameSpawn.java
Normal file
File diff suppressed because it is too large
Load Diff
848
src/main/java/lwjake2/game/GameTarget.java
Normal file
848
src/main/java/lwjake2/game/GameTarget.java
Normal file
@@ -0,0 +1,848 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
public class GameTarget {
|
||||
|
||||
public static void SP_target_temp_entity(edict_t ent) {
|
||||
ent.use = Use_Target_Tent;
|
||||
}
|
||||
|
||||
public static void SP_target_speaker(edict_t ent) {
|
||||
//char buffer[MAX_QPATH];
|
||||
String buffer;
|
||||
|
||||
if (GameBase.st.noise == null) {
|
||||
GameBase.gi.dprintf("target_speaker with no noise set at "
|
||||
+ Lib.vtos(ent.s.origin) + "\n");
|
||||
return;
|
||||
}
|
||||
if (GameBase.st.noise.indexOf(".wav") < 0)
|
||||
buffer = "" + GameBase.st.noise + ".wav";
|
||||
else
|
||||
buffer = GameBase.st.noise;
|
||||
|
||||
ent.noise_index = GameBase.gi.soundindex(buffer);
|
||||
|
||||
if (ent.volume == 0)
|
||||
ent.volume = 1.0f;
|
||||
|
||||
if (ent.attenuation == 0)
|
||||
ent.attenuation = 1.0f;
|
||||
else if (ent.attenuation == -1) // use -1 so 0 defaults to 1
|
||||
ent.attenuation = 0;
|
||||
|
||||
// check for prestarted looping sound
|
||||
if ((ent.spawnflags & 1) != 0)
|
||||
ent.s.sound = ent.noise_index;
|
||||
|
||||
ent.use = Use_Target_Speaker;
|
||||
|
||||
// must link the entity so we get areas and clusters so
|
||||
// the server can determine who to send updates to
|
||||
GameBase.gi.linkentity(ent);
|
||||
}
|
||||
|
||||
/**
|
||||
* QUAKED target_help (1 0 1) (-16 -16 -24) (16 16 24) help1 When fired, the
|
||||
* "message" key becomes the current personal computer string, and the
|
||||
* message light will be set on all clients status bars.
|
||||
*/
|
||||
public static void SP_target_help(edict_t ent) {
|
||||
if (GameBase.deathmatch.value != 0) { // auto-remove for deathmatch
|
||||
GameUtil.G_FreeEdict(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent.message == null) {
|
||||
GameBase.gi.dprintf(ent.classname + " with no message at "
|
||||
+ Lib.vtos(ent.s.origin) + "\n");
|
||||
GameUtil.G_FreeEdict(ent);
|
||||
return;
|
||||
}
|
||||
ent.use = Use_Target_Help;
|
||||
}
|
||||
|
||||
public static void SP_target_secret(edict_t ent) {
|
||||
if (GameBase.deathmatch.value != 0) { // auto-remove for deathmatch
|
||||
GameUtil.G_FreeEdict(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
ent.use = use_target_secret;
|
||||
if (GameBase.st.noise == null)
|
||||
GameBase.st.noise = "misc/secret.wav";
|
||||
ent.noise_index = GameBase.gi.soundindex(GameBase.st.noise);
|
||||
ent.svflags = Defines.SVF_NOCLIENT;
|
||||
GameBase.level.total_secrets++;
|
||||
// map bug hack
|
||||
if (0 == Lib.Q_stricmp(GameBase.level.mapname, "mine3")
|
||||
&& ent.s.origin[0] == 280 && ent.s.origin[1] == -2048
|
||||
&& ent.s.origin[2] == -624)
|
||||
ent.message = "You have found a secret area.";
|
||||
}
|
||||
|
||||
public static void SP_target_goal(edict_t ent) {
|
||||
if (GameBase.deathmatch.value != 0) { // auto-remove for deathmatch
|
||||
GameUtil.G_FreeEdict(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
ent.use = use_target_goal;
|
||||
if (GameBase.st.noise == null)
|
||||
GameBase.st.noise = "misc/secret.wav";
|
||||
ent.noise_index = GameBase.gi.soundindex(GameBase.st.noise);
|
||||
ent.svflags = Defines.SVF_NOCLIENT;
|
||||
GameBase.level.total_goals++;
|
||||
}
|
||||
|
||||
public static void SP_target_explosion(edict_t ent) {
|
||||
ent.use = use_target_explosion;
|
||||
ent.svflags = Defines.SVF_NOCLIENT;
|
||||
}
|
||||
|
||||
public static void SP_target_changelevel(edict_t ent) {
|
||||
if (ent.map == null) {
|
||||
GameBase.gi.dprintf("target_changelevel with no map at "
|
||||
+ Lib.vtos(ent.s.origin) + "\n");
|
||||
GameUtil.G_FreeEdict(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
// ugly hack because *SOMEBODY* screwed up their map
|
||||
if ((Lib.Q_stricmp(GameBase.level.mapname, "fact1") == 0)
|
||||
&& (Lib.Q_stricmp(ent.map, "fact3") == 0))
|
||||
ent.map = "fact3$secret1";
|
||||
|
||||
ent.use = use_target_changelevel;
|
||||
ent.svflags = Defines.SVF_NOCLIENT;
|
||||
}
|
||||
|
||||
public static void SP_target_splash(edict_t self) {
|
||||
self.use = use_target_splash;
|
||||
GameBase.G_SetMovedir(self.s.angles, self.movedir);
|
||||
|
||||
if (0 == self.count)
|
||||
self.count = 32;
|
||||
|
||||
self.svflags = Defines.SVF_NOCLIENT;
|
||||
}
|
||||
|
||||
public static void SP_target_spawner(edict_t self) {
|
||||
self.use = use_target_spawner;
|
||||
self.svflags = Defines.SVF_NOCLIENT;
|
||||
if (self.speed != 0) {
|
||||
GameBase.G_SetMovedir(self.s.angles, self.movedir);
|
||||
Math3D.VectorScale(self.movedir, self.speed, self.movedir);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SP_target_blaster(edict_t self) {
|
||||
self.use = use_target_blaster;
|
||||
GameBase.G_SetMovedir(self.s.angles, self.movedir);
|
||||
self.noise_index = GameBase.gi.soundindex("weapons/laser2.wav");
|
||||
|
||||
if (0 == self.dmg)
|
||||
self.dmg = 15;
|
||||
if (0 == self.speed)
|
||||
self.speed = 1000;
|
||||
|
||||
self.svflags = Defines.SVF_NOCLIENT;
|
||||
}
|
||||
|
||||
public static void SP_target_crosslevel_trigger(edict_t self) {
|
||||
self.svflags = Defines.SVF_NOCLIENT;
|
||||
self.use = trigger_crosslevel_trigger_use;
|
||||
}
|
||||
|
||||
public static void SP_target_crosslevel_target(edict_t self) {
|
||||
if (0 == self.delay)
|
||||
self.delay = 1;
|
||||
self.svflags = Defines.SVF_NOCLIENT;
|
||||
|
||||
self.think = target_crosslevel_target_think;
|
||||
self.nextthink = GameBase.level.time + self.delay;
|
||||
}
|
||||
|
||||
public static void target_laser_on(edict_t self) {
|
||||
if (null == self.activator)
|
||||
self.activator = self;
|
||||
self.spawnflags |= 0x80000001;
|
||||
self.svflags &= ~Defines.SVF_NOCLIENT;
|
||||
target_laser_think.think(self);
|
||||
}
|
||||
|
||||
public static void target_laser_off(edict_t self) {
|
||||
self.spawnflags &= ~1;
|
||||
self.svflags |= Defines.SVF_NOCLIENT;
|
||||
self.nextthink = 0;
|
||||
}
|
||||
|
||||
public static void SP_target_laser(edict_t self) {
|
||||
// let everything else get spawned before we start firing
|
||||
self.think = target_laser_start;
|
||||
self.nextthink = GameBase.level.time + 1;
|
||||
}
|
||||
|
||||
public static void SP_target_lightramp(edict_t self) {
|
||||
if (self.message == null || self.message.length() != 2
|
||||
|| self.message.charAt(0) < 'a' || self.message.charAt(0) > 'z'
|
||||
|| self.message.charAt(1) < 'a' || self.message.charAt(1) > 'z'
|
||||
|| self.message.charAt(0) == self.message.charAt(1)) {
|
||||
GameBase.gi.dprintf("target_lightramp has bad ramp ("
|
||||
+ self.message + ") at " + Lib.vtos(self.s.origin) + "\n");
|
||||
GameUtil.G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameBase.deathmatch.value != 0) {
|
||||
GameUtil.G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.target == null) {
|
||||
GameBase.gi.dprintf(self.classname + " with no target at "
|
||||
+ Lib.vtos(self.s.origin) + "\n");
|
||||
GameUtil.G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
self.svflags |= Defines.SVF_NOCLIENT;
|
||||
self.use = target_lightramp_use;
|
||||
self.think = target_lightramp_think;
|
||||
|
||||
self.movedir[0] = self.message.charAt(0) - 'a';
|
||||
self.movedir[1] = self.message.charAt(1) - 'a';
|
||||
self.movedir[2] = (self.movedir[1] - self.movedir[0])
|
||||
/ (self.speed / Defines.FRAMETIME);
|
||||
}
|
||||
|
||||
public static void SP_target_earthquake(edict_t self) {
|
||||
if (null == self.targetname)
|
||||
GameBase.gi.dprintf("untargeted " + self.classname + " at "
|
||||
+ Lib.vtos(self.s.origin) + "\n");
|
||||
|
||||
if (0 == self.count)
|
||||
self.count = 5;
|
||||
|
||||
if (0 == self.speed)
|
||||
self.speed = 200;
|
||||
|
||||
self.svflags |= Defines.SVF_NOCLIENT;
|
||||
self.think = target_earthquake_think;
|
||||
self.use = target_earthquake_use;
|
||||
|
||||
self.noise_index = GameBase.gi.soundindex("world/quake.wav");
|
||||
}
|
||||
|
||||
/**
|
||||
* QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8) Fire an origin based
|
||||
* temp entity event to the clients. "style" type byte
|
||||
*/
|
||||
public static EntUseAdapter Use_Target_Tent = new EntUseAdapter() {
|
||||
public String getID() { return "Use_Target_Tent"; }
|
||||
public void use(edict_t ent, edict_t other, edict_t activator) {
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(ent.style);
|
||||
GameBase.gi.WritePosition(ent.s.origin);
|
||||
GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off
|
||||
* reliable "noise" wav file to play "attenuation" -1 = none, send to whole
|
||||
* level 1 = normal fighting sounds 2 = idle sound level 3 = ambient sound
|
||||
* level "volume" 0.0 to 1.0
|
||||
*
|
||||
* Normal sounds play each time the target is used. The reliable flag can be
|
||||
* set for crucial voiceovers.
|
||||
*
|
||||
* Looped sounds are always atten 3 / vol 1, and the use function toggles it
|
||||
* on/off. Multiple identical looping sounds will just increase volume
|
||||
* without any speed cost.
|
||||
*/
|
||||
public static EntUseAdapter Use_Target_Speaker = new EntUseAdapter() {
|
||||
public String getID() { return "Use_Target_Speaker"; }
|
||||
public void use(edict_t ent, edict_t other, edict_t activator) {
|
||||
int chan;
|
||||
|
||||
if ((ent.spawnflags & 3) != 0) { // looping sound toggles
|
||||
if (ent.s.sound != 0)
|
||||
ent.s.sound = 0; // turn it off
|
||||
else
|
||||
ent.s.sound = ent.noise_index; // start it
|
||||
} else { // normal sound
|
||||
if ((ent.spawnflags & 4) != 0)
|
||||
chan = Defines.CHAN_VOICE | Defines.CHAN_RELIABLE;
|
||||
else
|
||||
chan = Defines.CHAN_VOICE;
|
||||
// use a positioned_sound, because this entity won't normally be
|
||||
// sent to any clients because it is invisible
|
||||
GameBase.gi.positioned_sound(ent.s.origin, ent, chan,
|
||||
ent.noise_index, ent.volume, ent.attenuation, 0);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static EntUseAdapter Use_Target_Help = new EntUseAdapter() {
|
||||
public String getID() { return "Use_Target_Help"; }
|
||||
public void use(edict_t ent, edict_t other, edict_t activator) {
|
||||
|
||||
if ((ent.spawnflags & 1) != 0)
|
||||
GameBase.game.helpmessage1 = ent.message;
|
||||
else
|
||||
GameBase.game.helpmessage2 = ent.message;
|
||||
|
||||
GameBase.game.helpchanged++;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED target_secret (1 0 1) (-8 -8 -8) (8 8 8) Counts a secret found.
|
||||
* These are single use targets.
|
||||
*/
|
||||
static EntUseAdapter use_target_secret = new EntUseAdapter() {
|
||||
public String getID() { return "use_target_secret"; }
|
||||
public void use(edict_t ent, edict_t other, edict_t activator) {
|
||||
GameBase.gi.sound(ent, Defines.CHAN_VOICE, ent.noise_index, 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
|
||||
GameBase.level.found_secrets++;
|
||||
|
||||
GameUtil.G_UseTargets(ent, activator);
|
||||
GameUtil.G_FreeEdict(ent);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED target_goal (1 0 1) (-8 -8 -8) (8 8 8) Counts a goal completed.
|
||||
* These are single use targets.
|
||||
*/
|
||||
static EntUseAdapter use_target_goal = new EntUseAdapter() {
|
||||
public String getID() { return "use_target_goal"; }
|
||||
public void use(edict_t ent, edict_t other, edict_t activator) {
|
||||
GameBase.gi.sound(ent, Defines.CHAN_VOICE, ent.noise_index, 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
|
||||
GameBase.level.found_goals++;
|
||||
|
||||
if (GameBase.level.found_goals == GameBase.level.total_goals)
|
||||
GameBase.gi.configstring(Defines.CS_CDTRACK, "0");
|
||||
|
||||
GameUtil.G_UseTargets(ent, activator);
|
||||
GameUtil.G_FreeEdict(ent);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* QUAKED target_explosion (1 0 0) (-8 -8 -8) (8 8 8) Spawns an explosion
|
||||
* temporary entity when used.
|
||||
*
|
||||
* "delay" wait this long before going off "dmg" how much radius damage
|
||||
* should be done, defaults to 0
|
||||
*/
|
||||
static EntThinkAdapter target_explosion_explode = new EntThinkAdapter() {
|
||||
public String getID() { return "target_explosion_explode"; }
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
float save;
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(Defines.TE_EXPLOSION1);
|
||||
GameBase.gi.WritePosition(self.s.origin);
|
||||
GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PHS);
|
||||
|
||||
GameCombat.T_RadiusDamage(self, self.activator, self.dmg, null,
|
||||
self.dmg + 40, Defines.MOD_EXPLOSIVE);
|
||||
|
||||
save = self.delay;
|
||||
self.delay = 0;
|
||||
GameUtil.G_UseTargets(self, self.activator);
|
||||
self.delay = save;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static EntUseAdapter use_target_explosion = new EntUseAdapter() {
|
||||
public String getID() { return "use_target_explosion"; }
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
self.activator = activator;
|
||||
|
||||
if (0 == self.delay) {
|
||||
target_explosion_explode.think(self);
|
||||
return;
|
||||
}
|
||||
|
||||
self.think = target_explosion_explode;
|
||||
self.nextthink = GameBase.level.time + self.delay;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED target_changelevel (1 0 0) (-8 -8 -8) (8 8 8) Changes level to
|
||||
* "map" when fired
|
||||
*/
|
||||
static EntUseAdapter use_target_changelevel = new EntUseAdapter() {
|
||||
public String getID() { return "use_target_changelevel"; }
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
if (GameBase.level.intermissiontime != 0)
|
||||
return; // already activated
|
||||
|
||||
if (0 == GameBase.deathmatch.value && 0 == GameBase.coop.value) {
|
||||
if (GameBase.g_edicts[1].health <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// if noexit, do a ton of damage to other
|
||||
if (GameBase.deathmatch.value != 0
|
||||
&& 0 == ((int) GameBase.dmflags.value & Defines.DF_ALLOW_EXIT)
|
||||
&& other != GameBase.g_edicts[0] /* world */
|
||||
) {
|
||||
GameCombat.T_Damage(other, self, self, Globals.vec3_origin,
|
||||
other.s.origin, Globals.vec3_origin,
|
||||
10 * other.max_health, 1000, 0, Defines.MOD_EXIT);
|
||||
return;
|
||||
}
|
||||
|
||||
// if multiplayer, let everyone know who hit the exit
|
||||
if (GameBase.deathmatch.value != 0) {
|
||||
if (activator != null && activator.client != null)
|
||||
GameBase.gi.bprintf(Defines.PRINT_HIGH,
|
||||
activator.client.pers.netname
|
||||
+ " exited the level.\n");
|
||||
}
|
||||
|
||||
// if going to a new unit, clear cross triggers
|
||||
if (self.map.indexOf('*') > -1)
|
||||
GameBase.game.serverflags &= ~(Defines.SFL_CROSS_TRIGGER_MASK);
|
||||
|
||||
PlayerHud.BeginIntermission(self);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED target_splash (1 0 0) (-8 -8 -8) (8 8 8) Creates a particle splash
|
||||
* effect when used.
|
||||
*
|
||||
* Set "sounds" to one of the following: 1) sparks 2) blue water 3) brown
|
||||
* water 4) slime 5) lava 6) blood
|
||||
*
|
||||
* "count" how many pixels in the splash "dmg" if set, does a radius damage
|
||||
* at this location when it splashes useful for lava/sparks
|
||||
*/
|
||||
static EntUseAdapter use_target_splash = new EntUseAdapter() {
|
||||
public String getID() { return "use_target_splash"; }
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(Defines.TE_SPLASH);
|
||||
GameBase.gi.WriteByte(self.count);
|
||||
GameBase.gi.WritePosition(self.s.origin);
|
||||
GameBase.gi.WriteDir(self.movedir);
|
||||
GameBase.gi.WriteByte(self.sounds);
|
||||
GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS);
|
||||
|
||||
if (self.dmg != 0)
|
||||
GameCombat.T_RadiusDamage(self, activator, self.dmg, null,
|
||||
self.dmg + 40, Defines.MOD_SPLASH);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED target_spawner (1 0 0) (-8 -8 -8) (8 8 8) Set target to the type
|
||||
* of entity you want spawned. Useful for spawning monsters and gibs in the
|
||||
* factory levels.
|
||||
*
|
||||
* For monsters: Set direction to the facing you want it to have.
|
||||
*
|
||||
* For gibs: Set direction if you want it moving and speed how fast it
|
||||
* should be moving otherwise it will just be dropped
|
||||
*/
|
||||
|
||||
static EntUseAdapter use_target_spawner = new EntUseAdapter() {
|
||||
public String getID() { return "use_target_spawner"; }
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
edict_t ent;
|
||||
|
||||
ent = GameUtil.G_Spawn();
|
||||
ent.classname = self.target;
|
||||
Math3D.VectorCopy(self.s.origin, ent.s.origin);
|
||||
Math3D.VectorCopy(self.s.angles, ent.s.angles);
|
||||
GameSpawn.ED_CallSpawn(ent);
|
||||
GameBase.gi.unlinkentity(ent);
|
||||
GameUtil.KillBox(ent);
|
||||
GameBase.gi.linkentity(ent);
|
||||
if (self.speed != 0)
|
||||
Math3D.VectorCopy(self.movedir, ent.velocity);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED target_blaster (1 0 0) (-8 -8 -8) (8 8 8) NOTRAIL NOEFFECTS Fires
|
||||
* a blaster bolt in the set direction when triggered.
|
||||
*
|
||||
* dmg default is 15 speed default is 1000
|
||||
*/
|
||||
public static EntUseAdapter use_target_blaster = new EntUseAdapter() {
|
||||
public String getID() { return "use_target_blaster"; }
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
|
||||
/* Wait what - flibit
|
||||
int effect;
|
||||
|
||||
if ((self.spawnflags & 2) != 0)
|
||||
effect = 0;
|
||||
else if ((self.spawnflags & 1) != 0)
|
||||
effect = Defines.EF_HYPERBLASTER;
|
||||
else
|
||||
effect = Defines.EF_BLASTER;
|
||||
*/
|
||||
|
||||
GameWeapon.fire_blaster(self, self.s.origin, self.movedir, self.dmg,
|
||||
(int) self.speed, Defines.EF_BLASTER,
|
||||
Defines.MOD_TARGET_BLASTER != 0
|
||||
/* true */
|
||||
);
|
||||
GameBase.gi.sound(self, Defines.CHAN_VOICE, self.noise_index, 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED target_crosslevel_trigger (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1
|
||||
* trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 Once this
|
||||
* trigger is touched/used, any trigger_crosslevel_target with the same
|
||||
* trigger number is automatically used when a level is started within the
|
||||
* same unit. It is OK to check multiple triggers. Message, delay, target,
|
||||
* and killtarget also work.
|
||||
*/
|
||||
public static EntUseAdapter trigger_crosslevel_trigger_use = new EntUseAdapter() {
|
||||
public String getID() { return "trigger_crosslevel_trigger_use"; }
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
GameBase.game.serverflags |= self.spawnflags;
|
||||
GameUtil.G_FreeEdict(self);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED target_crosslevel_target (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1
|
||||
* trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 Triggered
|
||||
* by a trigger_crosslevel elsewhere within a unit. If multiple triggers are
|
||||
* checked, all must be true. Delay, target and killtarget also work.
|
||||
*
|
||||
* "delay" delay before using targets if the trigger has been activated
|
||||
* (default 1)
|
||||
*/
|
||||
static EntThinkAdapter target_crosslevel_target_think = new EntThinkAdapter() {
|
||||
public String getID() { return "target_crosslevel_target_think"; }
|
||||
public boolean think(edict_t self) {
|
||||
if (self.spawnflags == (GameBase.game.serverflags
|
||||
& Defines.SFL_CROSS_TRIGGER_MASK & self.spawnflags)) {
|
||||
GameUtil.G_UseTargets(self, self);
|
||||
GameUtil.G_FreeEdict(self);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE
|
||||
* YELLOW ORANGE FAT When triggered, fires a laser. You can either set a
|
||||
* target or a direction.
|
||||
*/
|
||||
public static EntThinkAdapter target_laser_think = new EntThinkAdapter() {
|
||||
public String getID() { return "target_laser_think"; }
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
edict_t ignore;
|
||||
float[] start = { 0, 0, 0 };
|
||||
float[] end = { 0, 0, 0 };
|
||||
trace_t tr;
|
||||
float[] point = { 0, 0, 0 };
|
||||
float[] last_movedir = { 0, 0, 0 };
|
||||
int count;
|
||||
|
||||
if ((self.spawnflags & 0x80000000) != 0)
|
||||
count = 8;
|
||||
else
|
||||
count = 4;
|
||||
|
||||
if (self.enemy != null) {
|
||||
Math3D.VectorCopy(self.movedir, last_movedir);
|
||||
Math3D.VectorMA(self.enemy.absmin, 0.5f, self.enemy.size, point);
|
||||
Math3D.VectorSubtract(point, self.s.origin, self.movedir);
|
||||
Math3D.VectorNormalize(self.movedir);
|
||||
if (!Math3D.VectorEquals(self.movedir, last_movedir))
|
||||
self.spawnflags |= 0x80000000;
|
||||
}
|
||||
|
||||
ignore = self;
|
||||
Math3D.VectorCopy(self.s.origin, start);
|
||||
Math3D.VectorMA(start, 2048, self.movedir, end);
|
||||
while (true) {
|
||||
tr = GameBase.gi.trace(start, null, null, end, ignore,
|
||||
Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER
|
||||
| Defines.CONTENTS_DEADMONSTER);
|
||||
|
||||
if (tr.ent == null)
|
||||
break;
|
||||
|
||||
// hurt it if we can
|
||||
if ((tr.ent.takedamage != 0)
|
||||
&& 0 == (tr.ent.flags & Defines.FL_IMMUNE_LASER))
|
||||
GameCombat.T_Damage(tr.ent, self, self.activator,
|
||||
self.movedir, tr.endpos, Globals.vec3_origin,
|
||||
self.dmg, 1, Defines.DAMAGE_ENERGY,
|
||||
Defines.MOD_TARGET_LASER);
|
||||
|
||||
// if we hit something that's not a monster or player or is
|
||||
// immune to lasers, we're done
|
||||
if (0 == (tr.ent.svflags & Defines.SVF_MONSTER)
|
||||
&& (null == tr.ent.client)) {
|
||||
if ((self.spawnflags & 0x80000000) != 0) {
|
||||
self.spawnflags &= ~0x80000000;
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(Defines.TE_LASER_SPARKS);
|
||||
GameBase.gi.WriteByte(count);
|
||||
GameBase.gi.WritePosition(tr.endpos);
|
||||
GameBase.gi.WriteDir(tr.plane.normal);
|
||||
GameBase.gi.WriteByte(self.s.skinnum);
|
||||
GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ignore = tr.ent;
|
||||
Math3D.VectorCopy(tr.endpos, start);
|
||||
}
|
||||
|
||||
Math3D.VectorCopy(tr.endpos, self.s.old_origin);
|
||||
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static EntUseAdapter target_laser_use = new EntUseAdapter() {
|
||||
public String getID() { return "target_laser_use"; }
|
||||
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
self.activator = activator;
|
||||
if ((self.spawnflags & 1) != 0)
|
||||
target_laser_off(self);
|
||||
else
|
||||
target_laser_on(self);
|
||||
}
|
||||
};
|
||||
|
||||
static EntThinkAdapter target_laser_start = new EntThinkAdapter() {
|
||||
public String getID() { return "target_laser_start"; }
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
self.movetype = Defines.MOVETYPE_NONE;
|
||||
self.solid = Defines.SOLID_NOT;
|
||||
self.s.renderfx |= Defines.RF_BEAM | Defines.RF_TRANSLUCENT;
|
||||
self.s.modelindex = 1; // must be non-zero
|
||||
|
||||
// set the beam diameter
|
||||
if ((self.spawnflags & 64) != 0)
|
||||
self.s.frame = 16;
|
||||
else
|
||||
self.s.frame = 4;
|
||||
|
||||
// set the color
|
||||
if ((self.spawnflags & 2) != 0)
|
||||
self.s.skinnum = 0xf2f2f0f0;
|
||||
else if ((self.spawnflags & 4) != 0)
|
||||
self.s.skinnum = 0xd0d1d2d3;
|
||||
else if ((self.spawnflags & 8) != 0)
|
||||
self.s.skinnum = 0xf3f3f1f1;
|
||||
else if ((self.spawnflags & 16) != 0)
|
||||
self.s.skinnum = 0xdcdddedf;
|
||||
else if ((self.spawnflags & 32) != 0)
|
||||
self.s.skinnum = 0xe0e1e2e3;
|
||||
|
||||
if (null == self.enemy) {
|
||||
if (self.target != null) {
|
||||
EdictIterator edit = GameBase.G_Find(null, GameBase.findByTarget,
|
||||
self.target);
|
||||
if (edit == null)
|
||||
GameBase.gi.dprintf(self.classname + " at "
|
||||
+ Lib.vtos(self.s.origin) + ": " + self.target
|
||||
+ " is a bad target\n");
|
||||
self.enemy = (edit != null ? edit.o : null);
|
||||
} else {
|
||||
GameBase.G_SetMovedir(self.s.angles, self.movedir);
|
||||
}
|
||||
}
|
||||
self.use = target_laser_use;
|
||||
self.think = target_laser_think;
|
||||
|
||||
if (0 == self.dmg)
|
||||
self.dmg = 1;
|
||||
|
||||
Math3D.VectorSet(self.mins, -8, -8, -8);
|
||||
Math3D.VectorSet(self.maxs, 8, 8, 8);
|
||||
GameBase.gi.linkentity(self);
|
||||
|
||||
if ((self.spawnflags & 1) != 0)
|
||||
target_laser_on(self);
|
||||
else
|
||||
target_laser_off(self);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED target_lightramp (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE speed How
|
||||
* many seconds the ramping will take message two letters; starting
|
||||
* lightlevel and ending lightlevel
|
||||
*/
|
||||
|
||||
static EntThinkAdapter target_lightramp_think = new EntThinkAdapter() {
|
||||
public String getID() { return "target_lightramp_think"; }
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
char tmp[] = {(char) ('a' + (int) (self.movedir[0] + (GameBase.level.time - self.timestamp)
|
||||
/ Defines.FRAMETIME * self.movedir[2]))};
|
||||
|
||||
GameBase.gi.configstring(Defines.CS_LIGHTS + self.enemy.style,
|
||||
new String(tmp));
|
||||
|
||||
if ((GameBase.level.time - self.timestamp) < self.speed) {
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
} else if ((self.spawnflags & 1) != 0) {
|
||||
char temp;
|
||||
|
||||
temp = (char) self.movedir[0];
|
||||
self.movedir[0] = self.movedir[1];
|
||||
self.movedir[1] = temp;
|
||||
self.movedir[2] *= -1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static EntUseAdapter target_lightramp_use = new EntUseAdapter() {
|
||||
public String getID() { return "target_lightramp_use"; }
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
if (self.enemy == null) {
|
||||
edict_t e;
|
||||
|
||||
// check all the targets
|
||||
e = null;
|
||||
EdictIterator es = null;
|
||||
|
||||
while (true) {
|
||||
es = GameBase
|
||||
.G_Find(es, GameBase.findByTarget, self.target);
|
||||
|
||||
if (es == null)
|
||||
break;
|
||||
|
||||
e = es.o;
|
||||
|
||||
if (Lib.strcmp(e.classname, "light") != 0) {
|
||||
GameBase.gi.dprintf(self.classname + " at "
|
||||
+ Lib.vtos(self.s.origin));
|
||||
GameBase.gi.dprintf("target " + self.target + " ("
|
||||
+ e.classname + " at " + Lib.vtos(e.s.origin)
|
||||
+ ") is not a light\n");
|
||||
} else {
|
||||
self.enemy = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (null == self.enemy) {
|
||||
GameBase.gi.dprintf(self.classname + " target "
|
||||
+ self.target + " not found at "
|
||||
+ Lib.vtos(self.s.origin) + "\n");
|
||||
GameUtil.G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.timestamp = GameBase.level.time;
|
||||
target_lightramp_think.think(self);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED target_earthquake (1 0 0) (-8 -8 -8) (8 8 8) When triggered, this
|
||||
* initiates a level-wide earthquake. All players and monsters are affected.
|
||||
* "speed" severity of the quake (default:200) "count" duration of the quake
|
||||
* (default:5)
|
||||
*/
|
||||
|
||||
static EntThinkAdapter target_earthquake_think = new EntThinkAdapter() {
|
||||
public String getID() { return "target_earthquake_think"; }
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
int i;
|
||||
edict_t e;
|
||||
|
||||
if (self.last_move_time < GameBase.level.time) {
|
||||
GameBase.gi.positioned_sound(self.s.origin, self,
|
||||
Defines.CHAN_AUTO, self.noise_index, 1.0f,
|
||||
Defines.ATTN_NONE, 0);
|
||||
self.last_move_time = GameBase.level.time + 0.5f;
|
||||
}
|
||||
|
||||
for (i = 1; i < GameBase.num_edicts; i++) {
|
||||
e = GameBase.g_edicts[i];
|
||||
|
||||
if (!e.inuse)
|
||||
continue;
|
||||
if (null == e.client)
|
||||
continue;
|
||||
if (null == e.groundentity)
|
||||
continue;
|
||||
|
||||
e.groundentity = null;
|
||||
e.velocity[0] += Lib.crandom() * 150;
|
||||
e.velocity[1] += Lib.crandom() * 150;
|
||||
e.velocity[2] = self.speed * (100.0f / e.mass);
|
||||
}
|
||||
|
||||
if (GameBase.level.time < self.timestamp)
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static EntUseAdapter target_earthquake_use = new EntUseAdapter() {
|
||||
public String getID() { return "target_earthquake_use"; }
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
self.timestamp = GameBase.level.time + self.count;
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
self.activator = activator;
|
||||
self.last_move_time = 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
583
src/main/java/lwjake2/game/GameTrigger.java
Normal file
583
src/main/java/lwjake2/game/GameTrigger.java
Normal file
@@ -0,0 +1,583 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
public class GameTrigger {
|
||||
|
||||
public static void InitTrigger(edict_t self) {
|
||||
if (!Math3D.VectorEquals(self.s.angles, Globals.vec3_origin))
|
||||
GameBase.G_SetMovedir(self.s.angles, self.movedir);
|
||||
|
||||
self.solid = Defines.SOLID_TRIGGER;
|
||||
self.movetype = Defines.MOVETYPE_NONE;
|
||||
GameBase.gi.setmodel(self, self.model);
|
||||
self.svflags = Defines.SVF_NOCLIENT;
|
||||
}
|
||||
|
||||
// the trigger was just activated
|
||||
// ent.activator should be set to the activator so it can be held through a
|
||||
// delay so wait for the delay time before firing
|
||||
public static void multi_trigger(edict_t ent) {
|
||||
if (ent.nextthink != 0)
|
||||
return; // already been triggered
|
||||
|
||||
GameUtil.G_UseTargets(ent, ent.activator);
|
||||
|
||||
if (ent.wait > 0) {
|
||||
ent.think = multi_wait;
|
||||
ent.nextthink = GameBase.level.time + ent.wait;
|
||||
} else { // we can't just remove (self) here, because this is a touch
|
||||
// function
|
||||
// called while looping through area links...
|
||||
ent.touch = null;
|
||||
ent.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
ent.think = GameUtil.G_FreeEdictA;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SP_trigger_multiple(edict_t ent) {
|
||||
if (ent.sounds == 1)
|
||||
ent.noise_index = GameBase.gi.soundindex("misc/secret.wav");
|
||||
else if (ent.sounds == 2)
|
||||
ent.noise_index = GameBase.gi.soundindex("misc/talk.wav");
|
||||
else if (ent.sounds == 3)
|
||||
ent.noise_index = GameBase.gi.soundindex("misc/trigger1.wav");
|
||||
|
||||
if (ent.wait == 0)
|
||||
ent.wait = 0.2f;
|
||||
|
||||
ent.touch = Touch_Multi;
|
||||
ent.movetype = Defines.MOVETYPE_NONE;
|
||||
ent.svflags |= Defines.SVF_NOCLIENT;
|
||||
|
||||
if ((ent.spawnflags & 4) != 0) {
|
||||
ent.solid = Defines.SOLID_NOT;
|
||||
ent.use = trigger_enable;
|
||||
} else {
|
||||
ent.solid = Defines.SOLID_TRIGGER;
|
||||
ent.use = Use_Multi;
|
||||
}
|
||||
|
||||
if (!Math3D.VectorEquals(ent.s.angles, Globals.vec3_origin))
|
||||
GameBase.G_SetMovedir(ent.s.angles, ent.movedir);
|
||||
|
||||
GameBase.gi.setmodel(ent, ent.model);
|
||||
GameBase.gi.linkentity(ent);
|
||||
}
|
||||
|
||||
/**
|
||||
* QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED Triggers once, then
|
||||
* removes itself. You must set the key "target" to the name of another
|
||||
* object in the level that has a matching "targetname".
|
||||
*
|
||||
* If TRIGGERED, this trigger must be triggered before it is live.
|
||||
*
|
||||
* sounds 1) secret 2) beep beep 3) large switch 4)
|
||||
*
|
||||
* "message" string to be displayed when triggered
|
||||
*/
|
||||
|
||||
public static void SP_trigger_once(edict_t ent) {
|
||||
// make old maps work because I messed up on flag assignments here
|
||||
// triggered was on bit 1 when it should have been on bit 4
|
||||
if ((ent.spawnflags & 1) != 0) {
|
||||
float[] v = { 0, 0, 0 };
|
||||
|
||||
Math3D.VectorMA(ent.mins, 0.5f, ent.size, v);
|
||||
ent.spawnflags &= ~1;
|
||||
ent.spawnflags |= 4;
|
||||
GameBase.gi.dprintf("fixed TRIGGERED flag on " + ent.classname
|
||||
+ " at " + Lib.vtos(v) + "\n");
|
||||
}
|
||||
|
||||
ent.wait = -1;
|
||||
SP_trigger_multiple(ent);
|
||||
}
|
||||
|
||||
public static void SP_trigger_relay(edict_t self) {
|
||||
self.use = trigger_relay_use;
|
||||
}
|
||||
|
||||
public static void SP_trigger_key(edict_t self) {
|
||||
if (GameBase.st.item == null) {
|
||||
GameBase.gi.dprintf("no key item for trigger_key at "
|
||||
+ Lib.vtos(self.s.origin) + "\n");
|
||||
return;
|
||||
}
|
||||
self.item = GameItems.FindItemByClassname(GameBase.st.item);
|
||||
|
||||
if (null == self.item) {
|
||||
GameBase.gi.dprintf("item " + GameBase.st.item
|
||||
+ " not found for trigger_key at "
|
||||
+ Lib.vtos(self.s.origin) + "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.target == null) {
|
||||
GameBase.gi.dprintf(self.classname + " at "
|
||||
+ Lib.vtos(self.s.origin) + " has no target\n");
|
||||
return;
|
||||
}
|
||||
|
||||
GameBase.gi.soundindex("misc/keytry.wav");
|
||||
GameBase.gi.soundindex("misc/keyuse.wav");
|
||||
|
||||
self.use = trigger_key_use;
|
||||
}
|
||||
|
||||
public static void SP_trigger_counter(edict_t self) {
|
||||
self.wait = -1;
|
||||
if (0 == self.count)
|
||||
self.count = 2;
|
||||
|
||||
self.use = trigger_counter_use;
|
||||
}
|
||||
|
||||
/*
|
||||
* ==============================================================================
|
||||
*
|
||||
* trigger_always
|
||||
*
|
||||
* ==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8) This trigger will
|
||||
* always fire. It is activated by the world.
|
||||
*/
|
||||
public static void SP_trigger_always(edict_t ent) {
|
||||
// we must have some delay to make sure our use targets are present
|
||||
if (ent.delay < 0.2f)
|
||||
ent.delay = 0.2f;
|
||||
GameUtil.G_UseTargets(ent, ent);
|
||||
}
|
||||
|
||||
/*
|
||||
* QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE Pushes the player "speed"
|
||||
* defaults to 1000
|
||||
*/
|
||||
public static void SP_trigger_push(edict_t self) {
|
||||
InitTrigger(self);
|
||||
windsound = GameBase.gi.soundindex("misc/windfly.wav");
|
||||
self.touch = trigger_push_touch;
|
||||
if (0 == self.speed)
|
||||
self.speed = 1000;
|
||||
GameBase.gi.linkentity(self);
|
||||
}
|
||||
|
||||
public static void SP_trigger_hurt(edict_t self) {
|
||||
InitTrigger(self);
|
||||
|
||||
self.noise_index = GameBase.gi.soundindex("world/electro.wav");
|
||||
self.touch = hurt_touch;
|
||||
|
||||
if (0 == self.dmg)
|
||||
self.dmg = 5;
|
||||
|
||||
if ((self.spawnflags & 1) != 0)
|
||||
self.solid = Defines.SOLID_NOT;
|
||||
else
|
||||
self.solid = Defines.SOLID_TRIGGER;
|
||||
|
||||
if ((self.spawnflags & 2) != 0)
|
||||
self.use = hurt_use;
|
||||
|
||||
GameBase.gi.linkentity(self);
|
||||
}
|
||||
|
||||
public static void SP_trigger_gravity(edict_t self) {
|
||||
if (GameBase.st.gravity == null) {
|
||||
GameBase.gi.dprintf("trigger_gravity without gravity set at "
|
||||
+ Lib.vtos(self.s.origin) + "\n");
|
||||
GameUtil.G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
InitTrigger(self);
|
||||
self.gravity = Lib.atoi(GameBase.st.gravity);
|
||||
self.touch = trigger_gravity_touch;
|
||||
}
|
||||
|
||||
public static void SP_trigger_monsterjump(edict_t self) {
|
||||
if (0 == self.speed)
|
||||
self.speed = 200;
|
||||
if (0 == GameBase.st.height)
|
||||
GameBase.st.height = 200;
|
||||
if (self.s.angles[Defines.YAW] == 0)
|
||||
self.s.angles[Defines.YAW] = 360;
|
||||
InitTrigger(self);
|
||||
self.touch = trigger_monsterjump_touch;
|
||||
self.movedir[2] = GameBase.st.height;
|
||||
}
|
||||
|
||||
// the wait time has passed, so set back up for another activation
|
||||
public static EntThinkAdapter multi_wait = new EntThinkAdapter() {
|
||||
public String getID(){ return "multi_wait"; }
|
||||
public boolean think(edict_t ent) {
|
||||
|
||||
ent.nextthink = 0;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static EntUseAdapter Use_Multi = new EntUseAdapter() {
|
||||
public String getID(){ return "Use_Multi"; }
|
||||
public void use(edict_t ent, edict_t other, edict_t activator) {
|
||||
ent.activator = activator;
|
||||
multi_trigger(ent);
|
||||
}
|
||||
};
|
||||
|
||||
static EntTouchAdapter Touch_Multi = new EntTouchAdapter() {
|
||||
public String getID(){ return "Touch_Multi"; }
|
||||
public void touch(edict_t self, edict_t other, cplane_t plane,
|
||||
csurface_t surf) {
|
||||
if (other.client != null) {
|
||||
if ((self.spawnflags & 2) != 0)
|
||||
return;
|
||||
} else if ((other.svflags & Defines.SVF_MONSTER) != 0) {
|
||||
if (0 == (self.spawnflags & 1))
|
||||
return;
|
||||
} else
|
||||
return;
|
||||
|
||||
if (!Math3D.VectorEquals(self.movedir, Globals.vec3_origin)) {
|
||||
float[] forward = { 0, 0, 0 };
|
||||
|
||||
Math3D.AngleVectors(other.s.angles, forward, null, null);
|
||||
if (Math3D.DotProduct(forward, self.movedir) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
self.activator = other;
|
||||
multi_trigger(self);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED
|
||||
* Variable sized repeatable trigger. Must be targeted at one or more
|
||||
* entities. If "delay" is set, the trigger waits some time after activating
|
||||
* before firing. "wait" : Seconds between triggerings. (.2 default) sounds
|
||||
* 1) secret 2) beep beep 3) large switch 4) set "message" to text string
|
||||
*/
|
||||
static EntUseAdapter trigger_enable = new EntUseAdapter() {
|
||||
public String getID(){ return "trigger_enable"; }
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
self.solid = Defines.SOLID_TRIGGER;
|
||||
self.use = Use_Multi;
|
||||
GameBase.gi.linkentity(self);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) This fixed size
|
||||
* trigger cannot be touched, it can only be fired by other events.
|
||||
*/
|
||||
public static EntUseAdapter trigger_relay_use = new EntUseAdapter() {
|
||||
public String getID(){ return "trigger_relay_use"; }
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
GameUtil.G_UseTargets(self, activator);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* ==============================================================================
|
||||
*
|
||||
* trigger_key
|
||||
*
|
||||
* ==============================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8) A relay trigger that
|
||||
* only fires it's targets if player has the proper key. Use "item" to
|
||||
* specify the required key, for example "key_data_cd"
|
||||
*/
|
||||
|
||||
static EntUseAdapter trigger_key_use = new EntUseAdapter() {
|
||||
public String getID(){ return "trigger_key_use"; }
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
int index;
|
||||
|
||||
if (self.item == null)
|
||||
return;
|
||||
if (activator.client == null)
|
||||
return;
|
||||
|
||||
index = GameItems.ITEM_INDEX(self.item);
|
||||
if (activator.client.pers.inventory[index] == 0) {
|
||||
if (GameBase.level.time < self.touch_debounce_time)
|
||||
return;
|
||||
self.touch_debounce_time = GameBase.level.time + 5.0f;
|
||||
GameBase.gi.centerprintf(activator, "You need the "
|
||||
+ self.item.pickup_name);
|
||||
GameBase.gi.sound(activator, Defines.CHAN_AUTO,
|
||||
GameBase.gi.soundindex("misc/keytry.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi
|
||||
.soundindex("misc/keyuse.wav"), 1, Defines.ATTN_NORM, 0);
|
||||
if (GameBase.coop.value != 0) {
|
||||
int player;
|
||||
edict_t ent;
|
||||
|
||||
if (Lib.strcmp(self.item.classname, "key_power_cube") == 0) {
|
||||
int cube;
|
||||
|
||||
for (cube = 0; cube < 8; cube++)
|
||||
if ((activator.client.pers.power_cubes & (1 << cube)) != 0)
|
||||
break;
|
||||
for (player = 1; player <= GameBase.game.maxclients; player++) {
|
||||
ent = GameBase.g_edicts[player];
|
||||
if (!ent.inuse)
|
||||
continue;
|
||||
if (null == ent.client)
|
||||
continue;
|
||||
if ((ent.client.pers.power_cubes & (1 << cube)) != 0) {
|
||||
ent.client.pers.inventory[index]--;
|
||||
ent.client.pers.power_cubes &= ~(1 << cube);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (player = 1; player <= GameBase.game.maxclients; player++) {
|
||||
ent = GameBase.g_edicts[player];
|
||||
if (!ent.inuse)
|
||||
continue;
|
||||
if (ent.client == null)
|
||||
continue;
|
||||
ent.client.pers.inventory[index] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
activator.client.pers.inventory[index]--;
|
||||
}
|
||||
|
||||
GameUtil.G_UseTargets(self, activator);
|
||||
|
||||
self.use = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* QUAKED trigger_counter (.5 .5 .5) ? nomessage Acts as an intermediary for
|
||||
* an action that takes multiple inputs.
|
||||
*
|
||||
* If nomessage is not set, t will print "1 more.. " etc when triggered and
|
||||
* "sequence complete" when finished.
|
||||
*
|
||||
* After the counter has been triggered "count" times (default 2), it will
|
||||
* fire all of it's targets and remove itself.
|
||||
*/
|
||||
static EntUseAdapter trigger_counter_use = new EntUseAdapter() {
|
||||
public String getID(){ return "trigger_counter_use"; }
|
||||
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
if (self.count == 0)
|
||||
return;
|
||||
|
||||
self.count--;
|
||||
|
||||
if (self.count != 0) {
|
||||
if (0 == (self.spawnflags & 1)) {
|
||||
GameBase.gi.centerprintf(activator, self.count
|
||||
+ " more to go...");
|
||||
GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi
|
||||
.soundindex("misc/talk1.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 == (self.spawnflags & 1)) {
|
||||
GameBase.gi.centerprintf(activator, "Sequence completed!");
|
||||
GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi
|
||||
.soundindex("misc/talk1.wav"), 1, Defines.ATTN_NORM, 0);
|
||||
}
|
||||
self.activator = activator;
|
||||
multi_trigger(self);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* ==============================================================================
|
||||
*
|
||||
* trigger_push
|
||||
*
|
||||
* ==============================================================================
|
||||
*/
|
||||
|
||||
public static final int PUSH_ONCE = 1;
|
||||
|
||||
public static int windsound;
|
||||
|
||||
static EntTouchAdapter trigger_push_touch = new EntTouchAdapter() {
|
||||
public String getID(){ return "trigger_push_touch"; }
|
||||
public void touch(edict_t self, edict_t other, cplane_t plane,
|
||||
csurface_t surf) {
|
||||
if (Lib.strcmp(other.classname, "grenade") == 0) {
|
||||
Math3D.VectorScale(self.movedir, self.speed * 10,
|
||||
other.velocity);
|
||||
} else if (other.health > 0) {
|
||||
Math3D.VectorScale(self.movedir, self.speed * 10,
|
||||
other.velocity);
|
||||
|
||||
if (other.client != null) {
|
||||
// don't take falling damage immediately from this
|
||||
Math3D.VectorCopy(other.velocity, other.client.oldvelocity);
|
||||
if (other.fly_sound_debounce_time < GameBase.level.time) {
|
||||
other.fly_sound_debounce_time = GameBase.level.time + 1.5f;
|
||||
GameBase.gi.sound(other, Defines.CHAN_AUTO, windsound,
|
||||
1, Defines.ATTN_NORM, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((self.spawnflags & PUSH_ONCE) != 0)
|
||||
GameUtil.G_FreeEdict(self);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION
|
||||
* SLOW Any entity that touches this will be hurt.
|
||||
*
|
||||
* It does dmg points of damage each server frame
|
||||
*
|
||||
* SILENT supresses playing the sound SLOW changes the damage rate to once
|
||||
* per second NO_PROTECTION *nothing* stops the damage
|
||||
*
|
||||
* "dmg" default 5 (whole numbers only)
|
||||
*
|
||||
*/
|
||||
static EntUseAdapter hurt_use = new EntUseAdapter() {
|
||||
public String getID(){ return "hurt_use"; }
|
||||
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
if (self.solid == Defines.SOLID_NOT)
|
||||
self.solid = Defines.SOLID_TRIGGER;
|
||||
else
|
||||
self.solid = Defines.SOLID_NOT;
|
||||
GameBase.gi.linkentity(self);
|
||||
|
||||
if (0 == (self.spawnflags & 2))
|
||||
self.use = null;
|
||||
}
|
||||
};
|
||||
|
||||
static EntTouchAdapter hurt_touch = new EntTouchAdapter() {
|
||||
public String getID(){ return "hurt_touch"; }
|
||||
public void touch(edict_t self, edict_t other, cplane_t plane,
|
||||
csurface_t surf) {
|
||||
int dflags;
|
||||
|
||||
if (other.takedamage == 0)
|
||||
return;
|
||||
|
||||
if (self.timestamp > GameBase.level.time)
|
||||
return;
|
||||
|
||||
if ((self.spawnflags & 16) != 0)
|
||||
self.timestamp = GameBase.level.time + 1;
|
||||
else
|
||||
self.timestamp = GameBase.level.time + Defines.FRAMETIME;
|
||||
|
||||
if (0 == (self.spawnflags & 4)) {
|
||||
if ((GameBase.level.framenum % 10) == 0)
|
||||
GameBase.gi.sound(other, Defines.CHAN_AUTO,
|
||||
self.noise_index, 1, Defines.ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
if ((self.spawnflags & 8) != 0)
|
||||
dflags = Defines.DAMAGE_NO_PROTECTION;
|
||||
else
|
||||
dflags = 0;
|
||||
GameCombat.T_Damage(other, self, self, Globals.vec3_origin,
|
||||
other.s.origin, Globals.vec3_origin, self.dmg, self.dmg,
|
||||
dflags, Defines.MOD_TRIGGER_HURT);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* ==============================================================================
|
||||
*
|
||||
* trigger_gravity
|
||||
*
|
||||
* ==============================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* QUAKED trigger_gravity (.5 .5 .5) ? Changes the touching entites gravity
|
||||
* to the value of "gravity". 1.0 is standard gravity for the level.
|
||||
*/
|
||||
|
||||
static EntTouchAdapter trigger_gravity_touch = new EntTouchAdapter() {
|
||||
public String getID(){ return "trigger_gravity_touch"; }
|
||||
|
||||
public void touch(edict_t self, edict_t other, cplane_t plane,
|
||||
csurface_t surf) {
|
||||
other.gravity = self.gravity;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* ==============================================================================
|
||||
*
|
||||
* trigger_monsterjump
|
||||
*
|
||||
* ==============================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* QUAKED trigger_monsterjump (.5 .5 .5) ? Walking monsters that touch this
|
||||
* will jump in the direction of the trigger's angle "speed" default to 200,
|
||||
* the speed thrown forward "height" default to 200, the speed thrown
|
||||
* upwards
|
||||
*/
|
||||
|
||||
static EntTouchAdapter trigger_monsterjump_touch = new EntTouchAdapter() {
|
||||
public String getID(){ return "trigger_monsterjump_touch"; }
|
||||
public void touch(edict_t self, edict_t other, cplane_t plane,
|
||||
csurface_t surf) {
|
||||
if ((other.flags & (Defines.FL_FLY | Defines.FL_SWIM)) != 0)
|
||||
return;
|
||||
if ((other.svflags & Defines.SVF_DEADMONSTER) != 0)
|
||||
return;
|
||||
if (0 == (other.svflags & Defines.SVF_MONSTER))
|
||||
return;
|
||||
|
||||
// set XY even if not on ground, so the jump will clear lips
|
||||
other.velocity[0] = self.movedir[0] * self.speed;
|
||||
other.velocity[1] = self.movedir[1] * self.speed;
|
||||
|
||||
if (other.groundentity != null)
|
||||
return;
|
||||
|
||||
other.groundentity = null;
|
||||
other.velocity[2] = self.movedir[2];
|
||||
}
|
||||
};
|
||||
}
|
||||
443
src/main/java/lwjake2/game/GameTurret.java
Normal file
443
src/main/java/lwjake2/game/GameTurret.java
Normal file
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.game.monsters.M_Infantry;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
public class GameTurret {
|
||||
|
||||
public static void AnglesNormalize(float[] vec) {
|
||||
while (vec[0] > 360)
|
||||
vec[0] -= 360;
|
||||
while (vec[0] < 0)
|
||||
vec[0] += 360;
|
||||
while (vec[1] > 360)
|
||||
vec[1] -= 360;
|
||||
while (vec[1] < 0)
|
||||
vec[1] += 360;
|
||||
}
|
||||
|
||||
public static float SnapToEights(float x) {
|
||||
x *= 8.0;
|
||||
if (x > 0.0)
|
||||
x += 0.5;
|
||||
else
|
||||
x -= 0.5;
|
||||
return 0.125f * (int) x;
|
||||
}
|
||||
|
||||
/**
|
||||
* QUAKED turret_breach (0 0 0) ? This portion of the turret can change both
|
||||
* pitch and yaw. The model should be made with a flat pitch. It (and the
|
||||
* associated base) need to be oriented towards 0. Use "angle" to set the
|
||||
* starting angle.
|
||||
*
|
||||
* "speed" default 50 "dmg" default 10 "angle" point this forward "target"
|
||||
* point this at an info_notnull at the muzzle tip "minpitch" min acceptable
|
||||
* pitch angle : default -30 "maxpitch" max acceptable pitch angle : default
|
||||
* 30 "minyaw" min acceptable yaw angle : default 0 "maxyaw" max acceptable
|
||||
* yaw angle : default 360
|
||||
*/
|
||||
|
||||
public static void turret_breach_fire(edict_t self) {
|
||||
float[] f = { 0, 0, 0 }, r = { 0, 0, 0 }, u = { 0, 0, 0 };
|
||||
float[] start = { 0, 0, 0 };
|
||||
int damage;
|
||||
int speed;
|
||||
|
||||
Math3D.AngleVectors(self.s.angles, f, r, u);
|
||||
Math3D.VectorMA(self.s.origin, self.move_origin[0], f, start);
|
||||
Math3D.VectorMA(start, self.move_origin[1], r, start);
|
||||
Math3D.VectorMA(start, self.move_origin[2], u, start);
|
||||
|
||||
damage = (int) (100 + Lib.random() * 50);
|
||||
speed = (int) (550 + 50 * GameBase.skill.value);
|
||||
GameWeapon.fire_rocket(self.teammaster.owner, start, f, damage, speed, 150,
|
||||
damage);
|
||||
GameBase.gi.positioned_sound(start, self, Defines.CHAN_WEAPON,
|
||||
GameBase.gi.soundindex("weapons/rocklf1a.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
public static void SP_turret_breach(edict_t self) {
|
||||
self.solid = Defines.SOLID_BSP;
|
||||
self.movetype = Defines.MOVETYPE_PUSH;
|
||||
GameBase.gi.setmodel(self, self.model);
|
||||
|
||||
if (self.speed == 0)
|
||||
self.speed = 50;
|
||||
if (self.dmg == 0)
|
||||
self.dmg = 10;
|
||||
|
||||
if (GameBase.st.minpitch == 0)
|
||||
GameBase.st.minpitch = -30;
|
||||
if (GameBase.st.maxpitch == 0)
|
||||
GameBase.st.maxpitch = 30;
|
||||
if (GameBase.st.maxyaw == 0)
|
||||
GameBase.st.maxyaw = 360;
|
||||
|
||||
self.pos1[Defines.PITCH] = -1 * GameBase.st.minpitch;
|
||||
self.pos1[Defines.YAW] = GameBase.st.minyaw;
|
||||
self.pos2[Defines.PITCH] = -1 * GameBase.st.maxpitch;
|
||||
self.pos2[Defines.YAW] = GameBase.st.maxyaw;
|
||||
|
||||
self.ideal_yaw = self.s.angles[Defines.YAW];
|
||||
self.move_angles[Defines.YAW] = self.ideal_yaw;
|
||||
|
||||
self.blocked = turret_blocked;
|
||||
|
||||
self.think = turret_breach_finish_init;
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
GameBase.gi.linkentity(self);
|
||||
}
|
||||
|
||||
/**
|
||||
* QUAKED turret_base (0 0 0) ? This portion of the turret changes yaw only.
|
||||
* MUST be teamed with a turret_breach.
|
||||
*/
|
||||
|
||||
public static void SP_turret_base(edict_t self) {
|
||||
self.solid = Defines.SOLID_BSP;
|
||||
self.movetype = Defines.MOVETYPE_PUSH;
|
||||
GameBase.gi.setmodel(self, self.model);
|
||||
self.blocked = turret_blocked;
|
||||
GameBase.gi.linkentity(self);
|
||||
}
|
||||
|
||||
public static void SP_turret_driver(edict_t self) {
|
||||
if (GameBase.deathmatch.value != 0) {
|
||||
GameUtil.G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
self.movetype = Defines.MOVETYPE_PUSH;
|
||||
self.solid = Defines.SOLID_BBOX;
|
||||
self.s.modelindex = GameBase.gi
|
||||
.modelindex("models/monsters/infantry/tris.md2");
|
||||
Math3D.VectorSet(self.mins, -16, -16, -24);
|
||||
Math3D.VectorSet(self.maxs, 16, 16, 32);
|
||||
|
||||
self.health = 100;
|
||||
self.gib_health = 0;
|
||||
self.mass = 200;
|
||||
self.viewheight = 24;
|
||||
|
||||
self.die = turret_driver_die;
|
||||
self.monsterinfo.stand = M_Infantry.infantry_stand;
|
||||
|
||||
self.flags |= Defines.FL_NO_KNOCKBACK;
|
||||
|
||||
GameBase.level.total_monsters++;
|
||||
|
||||
self.svflags |= Defines.SVF_MONSTER;
|
||||
self.s.renderfx |= Defines.RF_FRAMELERP;
|
||||
self.takedamage = Defines.DAMAGE_AIM;
|
||||
self.use = GameUtil.monster_use;
|
||||
self.clipmask = Defines.MASK_MONSTERSOLID;
|
||||
Math3D.VectorCopy(self.s.origin, self.s.old_origin);
|
||||
self.monsterinfo.aiflags |= Defines.AI_STAND_GROUND | Defines.AI_DUCKED;
|
||||
|
||||
if (GameBase.st.item != null) {
|
||||
self.item = GameItems.FindItemByClassname(GameBase.st.item);
|
||||
if (self.item == null)
|
||||
GameBase.gi.dprintf(self.classname + " at "
|
||||
+ Lib.vtos(self.s.origin) + " has bad item: "
|
||||
+ GameBase.st.item + "\n");
|
||||
}
|
||||
|
||||
self.think = turret_driver_link;
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
|
||||
GameBase.gi.linkentity(self);
|
||||
}
|
||||
|
||||
static EntBlockedAdapter turret_blocked = new EntBlockedAdapter() {
|
||||
public String getID() { return "turret_blocked"; }
|
||||
public void blocked(edict_t self, edict_t other) {
|
||||
edict_t attacker;
|
||||
|
||||
if (other.takedamage != 0) {
|
||||
if (self.teammaster.owner != null)
|
||||
attacker = self.teammaster.owner;
|
||||
else
|
||||
attacker = self.teammaster;
|
||||
GameCombat.T_Damage(other, self, attacker, Globals.vec3_origin,
|
||||
other.s.origin, Globals.vec3_origin,
|
||||
self.teammaster.dmg, 10, 0, Defines.MOD_CRUSH);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static EntThinkAdapter turret_breach_think = new EntThinkAdapter() {
|
||||
public String getID() { return "turret_breach_think"; }
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
edict_t ent;
|
||||
float[] current_angles = { 0, 0, 0 };
|
||||
float[] delta = { 0, 0, 0 };
|
||||
|
||||
Math3D.VectorCopy(self.s.angles, current_angles);
|
||||
AnglesNormalize(current_angles);
|
||||
|
||||
AnglesNormalize(self.move_angles);
|
||||
if (self.move_angles[Defines.PITCH] > 180)
|
||||
self.move_angles[Defines.PITCH] -= 360;
|
||||
|
||||
// clamp angles to mins & maxs
|
||||
if (self.move_angles[Defines.PITCH] > self.pos1[Defines.PITCH])
|
||||
self.move_angles[Defines.PITCH] = self.pos1[Defines.PITCH];
|
||||
else if (self.move_angles[Defines.PITCH] < self.pos2[Defines.PITCH])
|
||||
self.move_angles[Defines.PITCH] = self.pos2[Defines.PITCH];
|
||||
|
||||
if ((self.move_angles[Defines.YAW] < self.pos1[Defines.YAW])
|
||||
|| (self.move_angles[Defines.YAW] > self.pos2[Defines.YAW])) {
|
||||
float dmin, dmax;
|
||||
|
||||
dmin = Math.abs(self.pos1[Defines.YAW]
|
||||
- self.move_angles[Defines.YAW]);
|
||||
if (dmin < -180)
|
||||
dmin += 360;
|
||||
else if (dmin > 180)
|
||||
dmin -= 360;
|
||||
dmax = Math.abs(self.pos2[Defines.YAW]
|
||||
- self.move_angles[Defines.YAW]);
|
||||
if (dmax < -180)
|
||||
dmax += 360;
|
||||
else if (dmax > 180)
|
||||
dmax -= 360;
|
||||
if (Math.abs(dmin) < Math.abs(dmax))
|
||||
self.move_angles[Defines.YAW] = self.pos1[Defines.YAW];
|
||||
else
|
||||
self.move_angles[Defines.YAW] = self.pos2[Defines.YAW];
|
||||
}
|
||||
|
||||
Math3D.VectorSubtract(self.move_angles, current_angles, delta);
|
||||
if (delta[0] < -180)
|
||||
delta[0] += 360;
|
||||
else if (delta[0] > 180)
|
||||
delta[0] -= 360;
|
||||
if (delta[1] < -180)
|
||||
delta[1] += 360;
|
||||
else if (delta[1] > 180)
|
||||
delta[1] -= 360;
|
||||
delta[2] = 0;
|
||||
|
||||
if (delta[0] > self.speed * Defines.FRAMETIME)
|
||||
delta[0] = self.speed * Defines.FRAMETIME;
|
||||
if (delta[0] < -1 * self.speed * Defines.FRAMETIME)
|
||||
delta[0] = -1 * self.speed * Defines.FRAMETIME;
|
||||
if (delta[1] > self.speed * Defines.FRAMETIME)
|
||||
delta[1] = self.speed * Defines.FRAMETIME;
|
||||
if (delta[1] < -1 * self.speed * Defines.FRAMETIME)
|
||||
delta[1] = -1 * self.speed * Defines.FRAMETIME;
|
||||
|
||||
Math3D.VectorScale(delta, 1.0f / Defines.FRAMETIME, self.avelocity);
|
||||
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
|
||||
for (ent = self.teammaster; ent != null; ent = ent.teamchain)
|
||||
ent.avelocity[1] = self.avelocity[1];
|
||||
|
||||
// if we have adriver, adjust his velocities
|
||||
if (self.owner != null) {
|
||||
float angle;
|
||||
float target_z;
|
||||
float diff;
|
||||
float[] target = { 0, 0, 0 };
|
||||
float[] dir = { 0, 0, 0 };
|
||||
|
||||
// angular is easy, just copy ours
|
||||
self.owner.avelocity[0] = self.avelocity[0];
|
||||
self.owner.avelocity[1] = self.avelocity[1];
|
||||
|
||||
// x & y
|
||||
angle = self.s.angles[1] + self.owner.move_origin[1];
|
||||
angle *= (Math.PI * 2 / 360);
|
||||
target[0] = GameTurret.SnapToEights((float) (self.s.origin[0] +
|
||||
Math.cos(angle) * self.owner.move_origin[0]));
|
||||
target[1] = GameTurret.SnapToEights((float) (self.s.origin[1] +
|
||||
Math.sin(angle) * self.owner.move_origin[0]));
|
||||
target[2] = self.owner.s.origin[2];
|
||||
|
||||
Math3D.VectorSubtract(target, self.owner.s.origin, dir);
|
||||
self.owner.velocity[0] = dir[0] * 1.0f / Defines.FRAMETIME;
|
||||
self.owner.velocity[1] = dir[1] * 1.0f / Defines.FRAMETIME;
|
||||
|
||||
// z
|
||||
angle = self.s.angles[Defines.PITCH] * (float) (Math.PI * 2f / 360f);
|
||||
target_z = GameTurret.SnapToEights((float) (self.s.origin[2]
|
||||
+ self.owner.move_origin[0] * Math.tan(angle) + self.owner.move_origin[2]));
|
||||
|
||||
diff = target_z - self.owner.s.origin[2];
|
||||
self.owner.velocity[2] = diff * 1.0f / Defines.FRAMETIME;
|
||||
|
||||
if ((self.spawnflags & 65536) != 0) {
|
||||
turret_breach_fire(self);
|
||||
self.spawnflags &= ~65536;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static EntThinkAdapter turret_breach_finish_init = new EntThinkAdapter() {
|
||||
public String getID() { return "turret_breach_finish_init"; }
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
// get and save info for muzzle location
|
||||
if (self.target == null) {
|
||||
GameBase.gi.dprintf(self.classname + " at "
|
||||
+ Lib.vtos(self.s.origin) + " needs a target\n");
|
||||
} else {
|
||||
self.target_ent = GameBase.G_PickTarget(self.target);
|
||||
Math3D.VectorSubtract(self.target_ent.s.origin, self.s.origin,
|
||||
self.move_origin);
|
||||
GameUtil.G_FreeEdict(self.target_ent);
|
||||
}
|
||||
|
||||
self.teammaster.dmg = self.dmg;
|
||||
self.think = turret_breach_think;
|
||||
self.think.think(self);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* QUAKED turret_driver (1 .5 0) (-16 -16 -24) (16 16 32) Must NOT be on the
|
||||
* team with the rest of the turret parts. Instead it must target the
|
||||
* turret_breach.
|
||||
*/
|
||||
static EntDieAdapter turret_driver_die = new EntDieAdapter() {
|
||||
public String getID() { return "turret_driver_die"; }
|
||||
public void die(edict_t self, edict_t inflictor, edict_t attacker,
|
||||
int damage, float[] point) {
|
||||
|
||||
edict_t ent;
|
||||
|
||||
// level the gun
|
||||
self.target_ent.move_angles[0] = 0;
|
||||
|
||||
// remove the driver from the end of them team chain
|
||||
for (ent = self.target_ent.teammaster; ent.teamchain != self; ent = ent.teamchain)
|
||||
;
|
||||
ent.teamchain = null;
|
||||
self.teammaster = null;
|
||||
self.flags &= ~Defines.FL_TEAMSLAVE;
|
||||
|
||||
self.target_ent.owner = null;
|
||||
self.target_ent.teammaster.owner = null;
|
||||
|
||||
M_Infantry.infantry_die.die(self, inflictor, attacker, damage, null);
|
||||
}
|
||||
};
|
||||
|
||||
static EntThinkAdapter turret_driver_think = new EntThinkAdapter() {
|
||||
public String getID() { return "turret_driver_think"; }
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
float[] target = { 0, 0, 0 };
|
||||
float[] dir = { 0, 0, 0 };
|
||||
float reaction_time;
|
||||
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
|
||||
if (self.enemy != null
|
||||
&& (!self.enemy.inuse || self.enemy.health <= 0))
|
||||
self.enemy = null;
|
||||
|
||||
if (null == self.enemy) {
|
||||
if (!GameUtil.FindTarget(self))
|
||||
return true;
|
||||
self.monsterinfo.trail_time = GameBase.level.time;
|
||||
self.monsterinfo.aiflags &= ~Defines.AI_LOST_SIGHT;
|
||||
} else {
|
||||
if (GameUtil.visible(self, self.enemy)) {
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_LOST_SIGHT) != 0) {
|
||||
self.monsterinfo.trail_time = GameBase.level.time;
|
||||
self.monsterinfo.aiflags &= ~Defines.AI_LOST_SIGHT;
|
||||
}
|
||||
} else {
|
||||
self.monsterinfo.aiflags |= Defines.AI_LOST_SIGHT;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// let the turret know where we want it to aim
|
||||
Math3D.VectorCopy(self.enemy.s.origin, target);
|
||||
target[2] += self.enemy.viewheight;
|
||||
Math3D.VectorSubtract(target, self.target_ent.s.origin, dir);
|
||||
Math3D.vectoangles(dir, self.target_ent.move_angles);
|
||||
|
||||
// decide if we should shoot
|
||||
if (GameBase.level.time < self.monsterinfo.attack_finished)
|
||||
return true;
|
||||
|
||||
reaction_time = (3 - GameBase.skill.value) * 1.0f;
|
||||
if ((GameBase.level.time - self.monsterinfo.trail_time) < reaction_time)
|
||||
return true;
|
||||
|
||||
self.monsterinfo.attack_finished = GameBase.level.time
|
||||
+ reaction_time + 1.0f;
|
||||
//FIXME how do we really want to pass this along?
|
||||
self.target_ent.spawnflags |= 65536;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static EntThinkAdapter turret_driver_link = new EntThinkAdapter() {
|
||||
public String getID() { return "turret_driver_link"; }
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
float[] vec = { 0, 0, 0 };
|
||||
edict_t ent;
|
||||
|
||||
self.think = turret_driver_think;
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
|
||||
self.target_ent = GameBase.G_PickTarget(self.target);
|
||||
self.target_ent.owner = self;
|
||||
self.target_ent.teammaster.owner = self;
|
||||
Math3D.VectorCopy(self.target_ent.s.angles, self.s.angles);
|
||||
|
||||
vec[0] = self.target_ent.s.origin[0] - self.s.origin[0];
|
||||
vec[1] = self.target_ent.s.origin[1] - self.s.origin[1];
|
||||
vec[2] = 0;
|
||||
self.move_origin[0] = Math3D.VectorLength(vec);
|
||||
|
||||
Math3D.VectorSubtract(self.s.origin, self.target_ent.s.origin, vec);
|
||||
Math3D.vectoangles(vec, vec);
|
||||
AnglesNormalize(vec);
|
||||
|
||||
self.move_origin[1] = vec[1];
|
||||
self.move_origin[2] = self.s.origin[2] - self.target_ent.s.origin[2];
|
||||
|
||||
// add the driver to the end of them team chain
|
||||
for (ent = self.target_ent.teammaster; ent.teamchain != null; ent = ent.teamchain)
|
||||
;
|
||||
ent.teamchain = self;
|
||||
self.teammaster = self.target_ent.teammaster;
|
||||
self.flags |= Defines.FL_TEAMSLAVE;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
686
src/main/java/lwjake2/game/GameUtil.java
Normal file
686
src/main/java/lwjake2/game/GameUtil.java
Normal file
@@ -0,0 +1,686 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.client.M;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
public class GameUtil {
|
||||
|
||||
public static void checkClassname(edict_t ent) {
|
||||
|
||||
if (ent.classname == null) {
|
||||
Com.Printf("edict with classname = null: " + ent.index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the targets.
|
||||
*
|
||||
* The global "activator" should be set to the entity that initiated the
|
||||
* firing.
|
||||
*
|
||||
* If self.delay is set, a DelayedUse entity will be created that will
|
||||
* actually do the SUB_UseTargets after that many seconds have passed.
|
||||
*
|
||||
* Centerprints any self.message to the activator.
|
||||
*
|
||||
* Search for (string)targetname in all entities that match
|
||||
* (string)self.target and call their .use function
|
||||
*/
|
||||
|
||||
public static void G_UseTargets(edict_t ent, edict_t activator) {
|
||||
edict_t t;
|
||||
|
||||
checkClassname(ent);
|
||||
|
||||
// check for a delay
|
||||
if (ent.delay != 0) {
|
||||
// create a temp object to fire at a later time
|
||||
t = G_Spawn();
|
||||
t.classname = "DelayedUse";
|
||||
t.nextthink = GameBase.level.time + ent.delay;
|
||||
t.think = Think_Delay;
|
||||
t.activator = activator;
|
||||
if (activator == null)
|
||||
GameBase.gi.dprintf("Think_Delay with no activator\n");
|
||||
t.message = ent.message;
|
||||
t.target = ent.target;
|
||||
t.killtarget = ent.killtarget;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// print the message
|
||||
if ((ent.message != null)
|
||||
&& (activator.svflags & Defines.SVF_MONSTER) == 0) {
|
||||
GameBase.gi.centerprintf(activator, "" + ent.message);
|
||||
if (ent.noise_index != 0)
|
||||
GameBase.gi.sound(activator, Defines.CHAN_AUTO,
|
||||
ent.noise_index, 1, Defines.ATTN_NORM, 0);
|
||||
else
|
||||
GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi
|
||||
.soundindex("misc/talk1.wav"), 1, Defines.ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
// kill killtargets
|
||||
EdictIterator edit = null;
|
||||
|
||||
if (ent.killtarget != null) {
|
||||
while ((edit = GameBase.G_Find(edit, GameBase.findByTarget,
|
||||
ent.killtarget)) != null) {
|
||||
t = edit.o;
|
||||
G_FreeEdict(t);
|
||||
if (!ent.inuse) {
|
||||
GameBase.gi
|
||||
.dprintf("entity was removed while using killtargets\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fire targets
|
||||
if (ent.target != null) {
|
||||
edit = null;
|
||||
while ((edit = GameBase.G_Find(edit, GameBase.findByTarget,
|
||||
ent.target)) != null) {
|
||||
t = edit.o;
|
||||
// doors fire area portals in a specific way
|
||||
if (Lib.Q_stricmp("func_areaportal", t.classname) == 0
|
||||
&& (Lib.Q_stricmp("func_door", ent.classname) == 0 || Lib
|
||||
.Q_stricmp("func_door_rotating", ent.classname) == 0))
|
||||
continue;
|
||||
|
||||
if (t == ent) {
|
||||
GameBase.gi.dprintf("WARNING: Entity used itself.\n");
|
||||
} else {
|
||||
if (t.use != null)
|
||||
t.use.use(t, ent, activator);
|
||||
}
|
||||
if (!ent.inuse) {
|
||||
GameBase.gi
|
||||
.dprintf("entity was removed while using targets\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void G_InitEdict(edict_t e, int i) {
|
||||
e.inuse = true;
|
||||
e.classname = "noclass";
|
||||
e.gravity = 1.0f;
|
||||
//e.s.number= e - g_edicts;
|
||||
e.s = new entity_state_t(e);
|
||||
e.s.number = i;
|
||||
e.index = i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Either finds a free edict, or allocates a new one. Try to avoid reusing
|
||||
* an entity that was recently freed, because it can cause the client to
|
||||
* think the entity morphed into something else instead of being removed and
|
||||
* recreated, which can cause interpolated angles and bad trails.
|
||||
*/
|
||||
public static edict_t G_Spawn() {
|
||||
int i;
|
||||
edict_t e = null;
|
||||
|
||||
for (i = (int) GameBase.maxclients.value + 1; i < GameBase.num_edicts; i++) {
|
||||
e = GameBase.g_edicts[i];
|
||||
// the first couple seconds of server time can involve a lot of
|
||||
// freeing and allocating, so relax the replacement policy
|
||||
if (!e.inuse
|
||||
&& (e.freetime < 2 || GameBase.level.time - e.freetime > 0.5)) {
|
||||
e = GameBase.g_edicts[i] = new edict_t(i);
|
||||
G_InitEdict(e, i);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == GameBase.game.maxentities)
|
||||
GameBase.gi.error("ED_Alloc: no free edicts");
|
||||
|
||||
e = GameBase.g_edicts[i] = new edict_t(i);
|
||||
GameBase.num_edicts++;
|
||||
G_InitEdict(e, i);
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the edict as free
|
||||
*/
|
||||
public static void G_FreeEdict(edict_t ed) {
|
||||
GameBase.gi.unlinkentity(ed); // unlink from world
|
||||
|
||||
//if ((ed - g_edicts) <= (maxclients.value + BODY_QUEUE_SIZE))
|
||||
if (ed.index <= (GameBase.maxclients.value + Defines.BODY_QUEUE_SIZE)) {
|
||||
// gi.dprintf("tried to free special edict\n");
|
||||
return;
|
||||
}
|
||||
|
||||
GameBase.g_edicts[ed.index] = new edict_t(ed.index);
|
||||
ed.classname = "freed";
|
||||
ed.freetime = GameBase.level.time;
|
||||
ed.inuse = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call after linking a new trigger in during gameplay to force all entities
|
||||
* it covers to immediately touch it.
|
||||
*/
|
||||
|
||||
public static void G_ClearEdict(edict_t ent) {
|
||||
int i = ent.index;
|
||||
GameBase.g_edicts[i] = new edict_t(i);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Kills all entities that would touch the proposed new positioning of ent.
|
||||
* Ent should be unlinked before calling this!
|
||||
*/
|
||||
|
||||
public static boolean KillBox(edict_t ent) {
|
||||
trace_t tr;
|
||||
|
||||
while (true) {
|
||||
tr = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs,
|
||||
ent.s.origin, null, Defines.MASK_PLAYERSOLID);
|
||||
if (tr.ent == null || tr.ent == GameBase.g_edicts[0])
|
||||
break;
|
||||
|
||||
// nail it
|
||||
GameCombat.T_Damage(tr.ent, ent, ent, Globals.vec3_origin, ent.s.origin,
|
||||
Globals.vec3_origin, 100000, 0,
|
||||
Defines.DAMAGE_NO_PROTECTION, Defines.MOD_TELEFRAG);
|
||||
|
||||
// if we didn't kill it, fail
|
||||
if (tr.ent.solid != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true; // all clear
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if two edicts are on the same team.
|
||||
*/
|
||||
public static boolean OnSameTeam(edict_t ent1, edict_t ent2) {
|
||||
if (0 == ((int) (GameBase.dmflags.value) & (Defines.DF_MODELTEAMS | Defines.DF_SKINTEAMS)))
|
||||
return false;
|
||||
|
||||
if (ClientTeam(ent1).equals(ClientTeam(ent2)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the team string of an entity
|
||||
* with respect to rteam_by_model and team_by_skin.
|
||||
*/
|
||||
static String ClientTeam(edict_t ent) {
|
||||
String value;
|
||||
|
||||
if (ent.client == null)
|
||||
return "";
|
||||
|
||||
value = Info.Info_ValueForKey(ent.client.pers.userinfo, "skin");
|
||||
|
||||
int p = value.indexOf("/");
|
||||
|
||||
if (p == -1)
|
||||
return value;
|
||||
|
||||
if (((int) (GameBase.dmflags.value) & Defines.DF_MODELTEAMS) != 0) {
|
||||
return value.substring(0, p);
|
||||
}
|
||||
|
||||
return value.substring(p + 1, value.length());
|
||||
}
|
||||
|
||||
static void ValidateSelectedItem(edict_t ent) {
|
||||
gclient_t cl;
|
||||
|
||||
cl = ent.client;
|
||||
|
||||
if (cl.pers.inventory[cl.pers.selected_item] != 0)
|
||||
return; // valid
|
||||
|
||||
GameItems.SelectNextItem(ent, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the range catagorization of an entity reletive to self 0 melee
|
||||
* range, will become hostile even if back is turned 1 visibility and
|
||||
* infront, or visibility and show hostile 2 infront and show hostile 3 only
|
||||
* triggered by damage.
|
||||
*/
|
||||
public static int range(edict_t self, edict_t other) {
|
||||
float[] v = { 0, 0, 0 };
|
||||
float len;
|
||||
|
||||
Math3D.VectorSubtract(self.s.origin, other.s.origin, v);
|
||||
len = Math3D.VectorLength(v);
|
||||
if (len < Defines.MELEE_DISTANCE)
|
||||
return Defines.RANGE_MELEE;
|
||||
if (len < 500)
|
||||
return Defines.RANGE_NEAR;
|
||||
if (len < 1000)
|
||||
return Defines.RANGE_MID;
|
||||
return Defines.RANGE_FAR;
|
||||
}
|
||||
|
||||
static void AttackFinished(edict_t self, float time) {
|
||||
self.monsterinfo.attack_finished = GameBase.level.time + time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the entity is in front (in sight) of self
|
||||
*/
|
||||
public static boolean infront(edict_t self, edict_t other) {
|
||||
float[] vec = { 0, 0, 0 };
|
||||
float dot;
|
||||
float[] forward = { 0, 0, 0 };
|
||||
|
||||
Math3D.AngleVectors(self.s.angles, forward, null, null);
|
||||
Math3D.VectorSubtract(other.s.origin, self.s.origin, vec);
|
||||
Math3D.VectorNormalize(vec);
|
||||
dot = Math3D.DotProduct(vec, forward);
|
||||
|
||||
if (dot > 0.3)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1 if the entity is visible to self, even if not infront().
|
||||
*/
|
||||
public static boolean visible(edict_t self, edict_t other) {
|
||||
float[] spot1 = { 0, 0, 0 };
|
||||
float[] spot2 = { 0, 0, 0 };
|
||||
trace_t trace;
|
||||
|
||||
Math3D.VectorCopy(self.s.origin, spot1);
|
||||
spot1[2] += self.viewheight;
|
||||
Math3D.VectorCopy(other.s.origin, spot2);
|
||||
spot2[2] += other.viewheight;
|
||||
trace = GameBase.gi.trace(spot1, Globals.vec3_origin,
|
||||
Globals.vec3_origin, spot2, self, Defines.MASK_OPAQUE);
|
||||
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a target.
|
||||
*
|
||||
* Self is currently not attacking anything, so try to find a target
|
||||
*
|
||||
* Returns TRUE if an enemy was sighted
|
||||
*
|
||||
* When a player fires a missile, the point of impact becomes a fakeplayer
|
||||
* so that monsters that see the impact will respond as if they had seen the
|
||||
* player.
|
||||
*
|
||||
* To avoid spending too much time, only a single client (or fakeclient) is
|
||||
* checked each frame. This means multi player games will have slightly
|
||||
* slower noticing monsters.
|
||||
*/
|
||||
static boolean FindTarget(edict_t self) {
|
||||
edict_t client;
|
||||
boolean heardit;
|
||||
int r;
|
||||
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_GOOD_GUY) != 0) {
|
||||
if (self.goalentity != null && self.goalentity.inuse
|
||||
&& self.goalentity.classname != null) {
|
||||
if (self.goalentity.classname.equals("target_actor"))
|
||||
return false;
|
||||
}
|
||||
|
||||
//FIXME look for monsters?
|
||||
return false;
|
||||
}
|
||||
|
||||
// if we're going to a combat point, just proceed
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_COMBAT_POINT) != 0)
|
||||
return false;
|
||||
|
||||
// if the first spawnflag bit is set, the monster will only wake up on
|
||||
// really seeing the player, not another monster getting angry or
|
||||
// hearing something
|
||||
// revised behavior so they will wake up if they "see" a player make a
|
||||
// noise but not weapon impact/explosion noises
|
||||
|
||||
heardit = false;
|
||||
if ((GameBase.level.sight_entity_framenum >= (GameBase.level.framenum - 1))
|
||||
&& 0 == (self.spawnflags & 1)) {
|
||||
client = GameBase.level.sight_entity;
|
||||
if (client.enemy == self.enemy)
|
||||
return false;
|
||||
} else if (GameBase.level.sound_entity_framenum >= (GameBase.level.framenum - 1)) {
|
||||
client = GameBase.level.sound_entity;
|
||||
heardit = true;
|
||||
} else if (null != (self.enemy)
|
||||
&& (GameBase.level.sound2_entity_framenum >= (GameBase.level.framenum - 1))
|
||||
&& 0 != (self.spawnflags & 1)) {
|
||||
client = GameBase.level.sound2_entity;
|
||||
heardit = true;
|
||||
} else {
|
||||
client = GameBase.level.sight_client;
|
||||
if (client == null)
|
||||
return false; // no clients to get mad at
|
||||
}
|
||||
|
||||
// if the entity went away, forget it
|
||||
if (!client.inuse)
|
||||
return false;
|
||||
|
||||
if (client.client != null) {
|
||||
if ((client.flags & Defines.FL_NOTARGET) != 0)
|
||||
return false;
|
||||
} else if ((client.svflags & Defines.SVF_MONSTER) != 0) {
|
||||
if (client.enemy == null)
|
||||
return false;
|
||||
if ((client.enemy.flags & Defines.FL_NOTARGET) != 0)
|
||||
return false;
|
||||
} else if (heardit) {
|
||||
if ((client.owner.flags & Defines.FL_NOTARGET) != 0)
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
|
||||
if (!heardit) {
|
||||
r = range(self, client);
|
||||
|
||||
if (r == Defines.RANGE_FAR)
|
||||
return false;
|
||||
|
||||
// this is where we would check invisibility
|
||||
// is client in an spot too dark to be seen?
|
||||
|
||||
if (client.light_level <= 5)
|
||||
return false;
|
||||
|
||||
if (!visible(self, client))
|
||||
return false;
|
||||
|
||||
|
||||
if (r == Defines.RANGE_NEAR) {
|
||||
if (client.show_hostile < GameBase.level.time
|
||||
&& !infront(self, client))
|
||||
return false;
|
||||
} else if (r == Defines.RANGE_MID) {
|
||||
if (!infront(self, client))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (client == self.enemy)
|
||||
return true; // JDC false;
|
||||
|
||||
self.enemy = client;
|
||||
|
||||
if (!self.enemy.classname.equals("player_noise")) {
|
||||
self.monsterinfo.aiflags &= ~Defines.AI_SOUND_TARGET;
|
||||
|
||||
if (self.enemy.client == null) {
|
||||
self.enemy = self.enemy.enemy;
|
||||
if (self.enemy.client == null) {
|
||||
self.enemy = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// heard it
|
||||
float[] temp = { 0, 0, 0 };
|
||||
|
||||
if ((self.spawnflags & 1) != 0) {
|
||||
if (!visible(self, client))
|
||||
return false;
|
||||
} else {
|
||||
if (!GameBase.gi.inPHS(self.s.origin, client.s.origin))
|
||||
return false;
|
||||
}
|
||||
|
||||
Math3D.VectorSubtract(client.s.origin, self.s.origin, temp);
|
||||
|
||||
if (Math3D.VectorLength(temp) > 1000) // too far to hear
|
||||
return false;
|
||||
|
||||
|
||||
// check area portals - if they are different and not connected then
|
||||
// we can't hear it
|
||||
if (client.areanum != self.areanum)
|
||||
if (!GameBase.gi.AreasConnected(self.areanum, client.areanum))
|
||||
return false;
|
||||
|
||||
self.ideal_yaw = Math3D.vectoyaw(temp);
|
||||
M.M_ChangeYaw(self);
|
||||
|
||||
// hunt the sound for a bit; hopefully find the real player
|
||||
self.monsterinfo.aiflags |= Defines.AI_SOUND_TARGET;
|
||||
|
||||
if (client == self.enemy)
|
||||
return true; // JDC false;
|
||||
|
||||
self.enemy = client;
|
||||
}
|
||||
|
||||
// got one
|
||||
FoundTarget(self);
|
||||
|
||||
if (0 == (self.monsterinfo.aiflags & Defines.AI_SOUND_TARGET)
|
||||
&& (self.monsterinfo.sight != null))
|
||||
self.monsterinfo.sight.interact(self, self.enemy);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void FoundTarget(edict_t self) {
|
||||
// let other monsters see this monster for a while
|
||||
if (self.enemy.client != null) {
|
||||
GameBase.level.sight_entity = self;
|
||||
GameBase.level.sight_entity_framenum = GameBase.level.framenum;
|
||||
GameBase.level.sight_entity.light_level = 128;
|
||||
}
|
||||
|
||||
self.show_hostile = (int) GameBase.level.time + 1; // wake up other
|
||||
// monsters
|
||||
|
||||
Math3D.VectorCopy(self.enemy.s.origin, self.monsterinfo.last_sighting);
|
||||
self.monsterinfo.trail_time = GameBase.level.time;
|
||||
|
||||
if (self.combattarget == null) {
|
||||
GameAI.HuntTarget(self);
|
||||
return;
|
||||
}
|
||||
|
||||
self.goalentity = self.movetarget = GameBase
|
||||
.G_PickTarget(self.combattarget);
|
||||
if (self.movetarget == null) {
|
||||
self.goalentity = self.movetarget = self.enemy;
|
||||
GameAI.HuntTarget(self);
|
||||
GameBase.gi.dprintf("" + self.classname + "at "
|
||||
+ Lib.vtos(self.s.origin) + ", combattarget "
|
||||
+ self.combattarget + " not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// clear out our combattarget, these are a one shot deal
|
||||
self.combattarget = null;
|
||||
self.monsterinfo.aiflags |= Defines.AI_COMBAT_POINT;
|
||||
|
||||
// clear the targetname, that point is ours!
|
||||
self.movetarget.targetname = null;
|
||||
self.monsterinfo.pausetime = 0;
|
||||
|
||||
// run for it
|
||||
self.monsterinfo.run.think(self);
|
||||
}
|
||||
|
||||
public static EntThinkAdapter Think_Delay = new EntThinkAdapter() {
|
||||
public String getID() { return "Think_Delay"; }
|
||||
public boolean think(edict_t ent) {
|
||||
G_UseTargets(ent, ent.activator);
|
||||
G_FreeEdict(ent);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static EntThinkAdapter G_FreeEdictA = new EntThinkAdapter() {
|
||||
public String getID() { return "G_FreeEdictA"; }
|
||||
public boolean think(edict_t ent) {
|
||||
G_FreeEdict(ent);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static EntThinkAdapter MegaHealth_think = new EntThinkAdapter() {
|
||||
public String getID() { return "MegaHealth_think"; }
|
||||
public boolean think(edict_t self) {
|
||||
if (self.owner.health > self.owner.max_health) {
|
||||
self.nextthink = GameBase.level.time + 1;
|
||||
self.owner.health -= 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!((self.spawnflags & Defines.DROPPED_ITEM) != 0)
|
||||
&& (GameBase.deathmatch.value != 0))
|
||||
GameItems.SetRespawn(self, 20);
|
||||
else
|
||||
G_FreeEdict(self);
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static EntThinkAdapter M_CheckAttack = new EntThinkAdapter() {
|
||||
public String getID() { return "M_CheckAttack"; }
|
||||
|
||||
public boolean think(edict_t self) {
|
||||
float[] spot1 = { 0, 0, 0 };
|
||||
|
||||
float[] spot2 = { 0, 0, 0 };
|
||||
float chance;
|
||||
trace_t tr;
|
||||
|
||||
if (self.enemy.health > 0) {
|
||||
// see if any entities are in the way of the shot
|
||||
Math3D.VectorCopy(self.s.origin, spot1);
|
||||
spot1[2] += self.viewheight;
|
||||
Math3D.VectorCopy(self.enemy.s.origin, spot2);
|
||||
spot2[2] += self.enemy.viewheight;
|
||||
|
||||
tr = GameBase.gi.trace(spot1, null, null, spot2, self,
|
||||
Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER
|
||||
| Defines.CONTENTS_SLIME
|
||||
| Defines.CONTENTS_LAVA
|
||||
| Defines.CONTENTS_WINDOW);
|
||||
|
||||
// do we have a clear shot?
|
||||
if (tr.ent != self.enemy)
|
||||
return false;
|
||||
}
|
||||
|
||||
// melee attack
|
||||
if (GameAI.enemy_range == Defines.RANGE_MELEE) {
|
||||
// don't always melee in easy mode
|
||||
if (GameBase.skill.value == 0 && (Lib.rand() & 3) != 0)
|
||||
return false;
|
||||
if (self.monsterinfo.melee != null)
|
||||
self.monsterinfo.attack_state = Defines.AS_MELEE;
|
||||
else
|
||||
self.monsterinfo.attack_state = Defines.AS_MISSILE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// missile attack
|
||||
if (self.monsterinfo.attack == null)
|
||||
return false;
|
||||
|
||||
if (GameBase.level.time < self.monsterinfo.attack_finished)
|
||||
return false;
|
||||
|
||||
if (GameAI.enemy_range == Defines.RANGE_FAR)
|
||||
return false;
|
||||
|
||||
if ((self.monsterinfo.aiflags & Defines.AI_STAND_GROUND) != 0) {
|
||||
chance = 0.4f;
|
||||
} else if (GameAI.enemy_range == Defines.RANGE_MELEE) {
|
||||
chance = 0.2f;
|
||||
} else if (GameAI.enemy_range == Defines.RANGE_NEAR) {
|
||||
chance = 0.1f;
|
||||
} else if (GameAI.enemy_range == Defines.RANGE_MID) {
|
||||
chance = 0.02f;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GameBase.skill.value == 0)
|
||||
chance *= 0.5;
|
||||
else if (GameBase.skill.value >= 2)
|
||||
chance *= 2;
|
||||
|
||||
if (Lib.random() < chance) {
|
||||
self.monsterinfo.attack_state = Defines.AS_MISSILE;
|
||||
self.monsterinfo.attack_finished = GameBase.level.time + 2
|
||||
* Lib.random();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((self.flags & Defines.FL_FLY) != 0) {
|
||||
if (Lib.random() < 0.3f)
|
||||
self.monsterinfo.attack_state = Defines.AS_SLIDING;
|
||||
else
|
||||
self.monsterinfo.attack_state = Defines.AS_STRAIGHT;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
static EntUseAdapter monster_use = new EntUseAdapter() {
|
||||
public String getID() { return "monster_use"; }
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
if (self.enemy != null)
|
||||
return;
|
||||
if (self.health <= 0)
|
||||
return;
|
||||
if ((activator.flags & Defines.FL_NOTARGET) != 0)
|
||||
return;
|
||||
if ((null == activator.client)
|
||||
&& 0 == (activator.monsterinfo.aiflags & Defines.AI_GOOD_GUY))
|
||||
return;
|
||||
|
||||
// delay reaction so if the monster is teleported, its sound is
|
||||
// still heard
|
||||
self.enemy = activator;
|
||||
FoundTarget(self);
|
||||
}
|
||||
};
|
||||
}
|
||||
972
src/main/java/lwjake2/game/GameWeapon.java
Normal file
972
src/main/java/lwjake2/game/GameWeapon.java
Normal file
@@ -0,0 +1,972 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
public class GameWeapon {
|
||||
|
||||
static EntTouchAdapter blaster_touch = new EntTouchAdapter() {
|
||||
public String getID() { return "blaster_touch"; }
|
||||
|
||||
public void touch(edict_t self, edict_t other, cplane_t plane,
|
||||
csurface_t surf) {
|
||||
int mod;
|
||||
|
||||
if (other == self.owner)
|
||||
return;
|
||||
|
||||
if (surf != null && (surf.flags & Defines.SURF_SKY) != 0) {
|
||||
GameUtil.G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.owner.client != null)
|
||||
PlayerWeapon.PlayerNoise(self.owner, self.s.origin,
|
||||
Defines.PNOISE_IMPACT);
|
||||
|
||||
if (other.takedamage != 0) {
|
||||
if ((self.spawnflags & 1) != 0)
|
||||
mod = Defines.MOD_HYPERBLASTER;
|
||||
else
|
||||
mod = Defines.MOD_BLASTER;
|
||||
|
||||
// bugfix null plane rst
|
||||
float[] normal;
|
||||
if (plane == null)
|
||||
normal = new float[3];
|
||||
else
|
||||
normal = plane.normal;
|
||||
|
||||
GameCombat.T_Damage(other, self, self.owner, self.velocity,
|
||||
self.s.origin, normal, self.dmg, 1,
|
||||
Defines.DAMAGE_ENERGY, mod);
|
||||
|
||||
} else {
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(Defines.TE_BLASTER);
|
||||
GameBase.gi.WritePosition(self.s.origin);
|
||||
if (plane == null)
|
||||
GameBase.gi.WriteDir(Globals.vec3_origin);
|
||||
else
|
||||
GameBase.gi.WriteDir(plane.normal);
|
||||
GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS);
|
||||
}
|
||||
|
||||
GameUtil.G_FreeEdict(self);
|
||||
}
|
||||
};
|
||||
|
||||
static EntThinkAdapter Grenade_Explode = new EntThinkAdapter() {
|
||||
public String getID() { return "Grenade_Explode"; }
|
||||
public boolean think(edict_t ent) {
|
||||
float[] origin = { 0, 0, 0 };
|
||||
int mod;
|
||||
|
||||
if (ent.owner.client != null)
|
||||
PlayerWeapon.PlayerNoise(ent.owner, ent.s.origin,
|
||||
Defines.PNOISE_IMPACT);
|
||||
|
||||
//FIXME: if we are onground then raise our Z just a bit since we
|
||||
// are a point?
|
||||
if (ent.enemy != null) {
|
||||
float points = 0;
|
||||
float[] v = { 0, 0, 0 };
|
||||
float[] dir = { 0, 0, 0 };
|
||||
|
||||
Math3D.VectorAdd(ent.enemy.mins, ent.enemy.maxs, v);
|
||||
Math3D.VectorMA(ent.enemy.s.origin, 0.5f, v, v);
|
||||
Math3D.VectorSubtract(ent.s.origin, v, v);
|
||||
points = ent.dmg - 0.5f * Math3D.VectorLength(v);
|
||||
Math3D.VectorSubtract(ent.enemy.s.origin, ent.s.origin, dir);
|
||||
if ((ent.spawnflags & 1) != 0)
|
||||
mod = Defines.MOD_HANDGRENADE;
|
||||
else
|
||||
mod = Defines.MOD_GRENADE;
|
||||
GameCombat.T_Damage(ent.enemy, ent, ent.owner, dir, ent.s.origin,
|
||||
Globals.vec3_origin, (int) points, (int) points,
|
||||
Defines.DAMAGE_RADIUS, mod);
|
||||
}
|
||||
|
||||
if ((ent.spawnflags & 2) != 0)
|
||||
mod = Defines.MOD_HELD_GRENADE;
|
||||
else if ((ent.spawnflags & 1) != 0)
|
||||
mod = Defines.MOD_HG_SPLASH;
|
||||
else
|
||||
mod = Defines.MOD_G_SPLASH;
|
||||
GameCombat.T_RadiusDamage(ent, ent.owner, ent.dmg, ent.enemy,
|
||||
ent.dmg_radius, mod);
|
||||
|
||||
Math3D.VectorMA(ent.s.origin, -0.02f, ent.velocity, origin);
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
if (ent.waterlevel != 0) {
|
||||
if (ent.groundentity != null)
|
||||
GameBase.gi.WriteByte(Defines.TE_GRENADE_EXPLOSION_WATER);
|
||||
else
|
||||
GameBase.gi.WriteByte(Defines.TE_ROCKET_EXPLOSION_WATER);
|
||||
} else {
|
||||
if (ent.groundentity != null)
|
||||
GameBase.gi.WriteByte(Defines.TE_GRENADE_EXPLOSION);
|
||||
else
|
||||
GameBase.gi.WriteByte(Defines.TE_ROCKET_EXPLOSION);
|
||||
}
|
||||
GameBase.gi.WritePosition(origin);
|
||||
GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PHS);
|
||||
|
||||
GameUtil.G_FreeEdict(ent);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
static EntTouchAdapter Grenade_Touch = new EntTouchAdapter() {
|
||||
public String getID() { return "Grenade_Touch"; }
|
||||
public void touch(edict_t ent, edict_t other, cplane_t plane,
|
||||
csurface_t surf) {
|
||||
if (other == ent.owner)
|
||||
return;
|
||||
|
||||
if (surf != null && 0 != (surf.flags & Defines.SURF_SKY)) {
|
||||
GameUtil.G_FreeEdict(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (other.takedamage == 0) {
|
||||
if ((ent.spawnflags & 1) != 0) {
|
||||
if (Lib.random() > 0.5f)
|
||||
GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi
|
||||
.soundindex("weapons/hgrenb1a.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
else
|
||||
GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi
|
||||
.soundindex("weapons/hgrenb2a.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
} else {
|
||||
GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi
|
||||
.soundindex("weapons/grenlb1b.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ent.enemy = other;
|
||||
Grenade_Explode.think(ent);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* =================
|
||||
* fire_rocket
|
||||
* =================
|
||||
*/
|
||||
static EntTouchAdapter rocket_touch = new EntTouchAdapter() {
|
||||
public String getID() { return "rocket_touch"; }
|
||||
public void touch(edict_t ent, edict_t other, cplane_t plane,
|
||||
csurface_t surf) {
|
||||
float[] origin = { 0, 0, 0 };
|
||||
int n;
|
||||
|
||||
if (other == ent.owner)
|
||||
return;
|
||||
|
||||
if (surf != null && (surf.flags & Defines.SURF_SKY) != 0) {
|
||||
GameUtil.G_FreeEdict(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent.owner.client != null)
|
||||
PlayerWeapon.PlayerNoise(ent.owner, ent.s.origin,
|
||||
Defines.PNOISE_IMPACT);
|
||||
|
||||
// calculate position for the explosion entity
|
||||
Math3D.VectorMA(ent.s.origin, -0.02f, ent.velocity, origin);
|
||||
|
||||
if (other.takedamage != 0) {
|
||||
GameCombat.T_Damage(other, ent, ent.owner, ent.velocity,
|
||||
ent.s.origin, plane.normal, ent.dmg, 0, 0,
|
||||
Defines.MOD_ROCKET);
|
||||
} else {
|
||||
// don't throw any debris in net games
|
||||
if (GameBase.deathmatch.value == 0 && 0 == GameBase.coop.value) {
|
||||
if ((surf != null)
|
||||
&& 0 == (surf.flags & (Defines.SURF_WARP
|
||||
| Defines.SURF_TRANS33
|
||||
| Defines.SURF_TRANS66 | Defines.SURF_FLOWING))) {
|
||||
n = Lib.rand() % 5;
|
||||
while (n-- > 0)
|
||||
GameMisc.ThrowDebris(ent,
|
||||
"models/objects/debris2/tris.md2", 2,
|
||||
ent.s.origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameCombat.T_RadiusDamage(ent, ent.owner, ent.radius_dmg, other,
|
||||
ent.dmg_radius, Defines.MOD_R_SPLASH);
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
if (ent.waterlevel != 0)
|
||||
GameBase.gi.WriteByte(Defines.TE_ROCKET_EXPLOSION_WATER);
|
||||
else
|
||||
GameBase.gi.WriteByte(Defines.TE_ROCKET_EXPLOSION);
|
||||
GameBase.gi.WritePosition(origin);
|
||||
GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PHS);
|
||||
|
||||
GameUtil.G_FreeEdict(ent);
|
||||
}
|
||||
};
|
||||
/*
|
||||
* =================
|
||||
* fire_bfg
|
||||
* =================
|
||||
*/
|
||||
static EntThinkAdapter bfg_explode = new EntThinkAdapter() {
|
||||
public String getID() { return "bfg_explode"; }
|
||||
public boolean think(edict_t self) {
|
||||
edict_t ent;
|
||||
float points;
|
||||
float[] v = { 0, 0, 0 };
|
||||
float dist;
|
||||
|
||||
EdictIterator edit = null;
|
||||
|
||||
if (self.s.frame == 0) {
|
||||
// the BFG effect
|
||||
ent = null;
|
||||
while ((edit = GameBase.findradius(edit, self.s.origin,
|
||||
self.dmg_radius)) != null) {
|
||||
ent = edit.o;
|
||||
if (ent.takedamage == 0)
|
||||
continue;
|
||||
if (ent == self.owner)
|
||||
continue;
|
||||
if (!GameCombat.CanDamage(ent, self))
|
||||
continue;
|
||||
if (!GameCombat.CanDamage(ent, self.owner))
|
||||
continue;
|
||||
|
||||
Math3D.VectorAdd(ent.mins, ent.maxs, v);
|
||||
Math3D.VectorMA(ent.s.origin, 0.5f, v, v);
|
||||
Math3D.VectorSubtract(self.s.origin, v, v);
|
||||
dist = Math3D.VectorLength(v);
|
||||
points = (float) (self.radius_dmg * (1.0 - Math.sqrt(dist
|
||||
/ self.dmg_radius)));
|
||||
if (ent == self.owner)
|
||||
points = points * 0.5f;
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(Defines.TE_BFG_EXPLOSION);
|
||||
GameBase.gi.WritePosition(ent.s.origin);
|
||||
GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PHS);
|
||||
GameCombat.T_Damage(ent, self, self.owner, self.velocity,
|
||||
ent.s.origin, Globals.vec3_origin, (int) points, 0,
|
||||
Defines.DAMAGE_ENERGY, Defines.MOD_BFG_EFFECT);
|
||||
}
|
||||
}
|
||||
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
self.s.frame++;
|
||||
if (self.s.frame == 5)
|
||||
self.think = GameUtil.G_FreeEdictA;
|
||||
return true;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
static EntTouchAdapter bfg_touch = new EntTouchAdapter() {
|
||||
public String getID() { return "bfg_touch"; }
|
||||
public void touch(edict_t self, edict_t other, cplane_t plane,
|
||||
csurface_t surf) {
|
||||
if (other == self.owner)
|
||||
return;
|
||||
|
||||
if (surf != null && (surf.flags & Defines.SURF_SKY) != 0) {
|
||||
GameUtil.G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.owner.client != null)
|
||||
PlayerWeapon.PlayerNoise(self.owner, self.s.origin,
|
||||
Defines.PNOISE_IMPACT);
|
||||
|
||||
// core explosion - prevents firing it into the wall/floor
|
||||
if (other.takedamage != 0)
|
||||
GameCombat.T_Damage(other, self, self.owner, self.velocity,
|
||||
self.s.origin, plane.normal, 200, 0, 0,
|
||||
Defines.MOD_BFG_BLAST);
|
||||
GameCombat.T_RadiusDamage(self, self.owner, 200, other, 100,
|
||||
Defines.MOD_BFG_BLAST);
|
||||
|
||||
GameBase.gi.sound(self, Defines.CHAN_VOICE, GameBase.gi
|
||||
.soundindex("weapons/bfg__x1b.wav"), 1, Defines.ATTN_NORM,
|
||||
0);
|
||||
self.solid = Defines.SOLID_NOT;
|
||||
self.touch = null;
|
||||
Math3D.VectorMA(self.s.origin, -1 * Defines.FRAMETIME,
|
||||
self.velocity, self.s.origin);
|
||||
Math3D.VectorClear(self.velocity);
|
||||
self.s.modelindex = GameBase.gi.modelindex("sprites/s_bfg3.sp2");
|
||||
self.s.frame = 0;
|
||||
self.s.sound = 0;
|
||||
self.s.effects &= ~Defines.EF_ANIM_ALLFAST;
|
||||
self.think = bfg_explode;
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
self.enemy = other;
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(Defines.TE_BFG_BIGEXPLOSION);
|
||||
GameBase.gi.WritePosition(self.s.origin);
|
||||
GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS);
|
||||
}
|
||||
};
|
||||
|
||||
static EntThinkAdapter bfg_think = new EntThinkAdapter() {
|
||||
public String getID() { return "bfg_think"; }
|
||||
public boolean think(edict_t self) {
|
||||
edict_t ent;
|
||||
edict_t ignore;
|
||||
float[] point = { 0, 0, 0 };
|
||||
float[] dir = { 0, 0, 0 };
|
||||
float[] start = { 0, 0, 0 };
|
||||
float[] end = { 0, 0, 0 };
|
||||
int dmg;
|
||||
trace_t tr;
|
||||
|
||||
if (GameBase.deathmatch.value != 0)
|
||||
dmg = 5;
|
||||
else
|
||||
dmg = 10;
|
||||
|
||||
EdictIterator edit = null;
|
||||
while ((edit = GameBase.findradius(edit, self.s.origin, 256)) != null) {
|
||||
ent = edit.o;
|
||||
|
||||
if (ent == self)
|
||||
continue;
|
||||
|
||||
if (ent == self.owner)
|
||||
continue;
|
||||
|
||||
if (ent.takedamage == 0)
|
||||
continue;
|
||||
|
||||
if (0 == (ent.svflags & Defines.SVF_MONSTER)
|
||||
&& (null == ent.client)
|
||||
&& (Lib.strcmp(ent.classname, "misc_explobox") != 0))
|
||||
continue;
|
||||
|
||||
Math3D.VectorMA(ent.absmin, 0.5f, ent.size, point);
|
||||
|
||||
Math3D.VectorSubtract(point, self.s.origin, dir);
|
||||
Math3D.VectorNormalize(dir);
|
||||
|
||||
ignore = self;
|
||||
Math3D.VectorCopy(self.s.origin, start);
|
||||
Math3D.VectorMA(start, 2048, dir, end);
|
||||
while (true) {
|
||||
tr = GameBase.gi.trace(start, null, null, end, ignore,
|
||||
Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER
|
||||
| Defines.CONTENTS_DEADMONSTER);
|
||||
|
||||
if (null == tr.ent)
|
||||
break;
|
||||
|
||||
// hurt it if we can
|
||||
if ((tr.ent.takedamage != 0)
|
||||
&& 0 == (tr.ent.flags & Defines.FL_IMMUNE_LASER)
|
||||
&& (tr.ent != self.owner))
|
||||
GameCombat.T_Damage(tr.ent, self, self.owner, dir,
|
||||
tr.endpos, Globals.vec3_origin, dmg, 1,
|
||||
Defines.DAMAGE_ENERGY, Defines.MOD_BFG_LASER);
|
||||
|
||||
// if we hit something that's not a monster or player we're
|
||||
// done
|
||||
if (0 == (tr.ent.svflags & Defines.SVF_MONSTER)
|
||||
&& (null == tr.ent.client)) {
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(Defines.TE_LASER_SPARKS);
|
||||
GameBase.gi.WriteByte(4);
|
||||
GameBase.gi.WritePosition(tr.endpos);
|
||||
GameBase.gi.WriteDir(tr.plane.normal);
|
||||
GameBase.gi.WriteByte(self.s.skinnum);
|
||||
GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS);
|
||||
break;
|
||||
}
|
||||
|
||||
ignore = tr.ent;
|
||||
Math3D.VectorCopy(tr.endpos, start);
|
||||
}
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(Defines.TE_BFG_LASER);
|
||||
GameBase.gi.WritePosition(self.s.origin);
|
||||
GameBase.gi.WritePosition(tr.endpos);
|
||||
GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PHS);
|
||||
}
|
||||
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* =================
|
||||
* check_dodge
|
||||
*
|
||||
* This is a support routine used when a client is firing a non-instant
|
||||
* attack weapon. It checks to see if a monster's dodge function should be
|
||||
* called.
|
||||
* =================
|
||||
*/
|
||||
static void check_dodge(edict_t self, float[] start, float[] dir, int speed) {
|
||||
float[] end = { 0, 0, 0 };
|
||||
float[] v = { 0, 0, 0 };
|
||||
trace_t tr;
|
||||
float eta;
|
||||
|
||||
// easy mode only ducks one quarter the time
|
||||
if (GameBase.skill.value == 0) {
|
||||
if (Lib.random() > 0.25)
|
||||
return;
|
||||
}
|
||||
Math3D.VectorMA(start, 8192, dir, end);
|
||||
tr = GameBase.gi.trace(start, null, null, end, self, Defines.MASK_SHOT);
|
||||
if ((tr.ent != null) && (tr.ent.svflags & Defines.SVF_MONSTER) != 0
|
||||
&& (tr.ent.health > 0) && (null != tr.ent.monsterinfo.dodge)
|
||||
&& GameUtil.infront(tr.ent, self)) {
|
||||
Math3D.VectorSubtract(tr.endpos, start, v);
|
||||
eta = (Math3D.VectorLength(v) - tr.ent.maxs[0]) / speed;
|
||||
tr.ent.monsterinfo.dodge.dodge(tr.ent, self, eta);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* =================
|
||||
* fire_hit
|
||||
*
|
||||
* Used for all impact (hit/punch/slash) attacks
|
||||
* =================
|
||||
*/
|
||||
public static boolean fire_hit(edict_t self, float[] aim, int damage,
|
||||
int kick) {
|
||||
trace_t tr;
|
||||
float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
|
||||
float[] v = { 0, 0, 0 };
|
||||
float[] point = { 0, 0, 0 };
|
||||
float range;
|
||||
float[] dir = { 0, 0, 0 };
|
||||
|
||||
//see if enemy is in range
|
||||
Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, dir);
|
||||
range = Math3D.VectorLength(dir);
|
||||
if (range > aim[0])
|
||||
return false;
|
||||
|
||||
if (aim[1] > self.mins[0] && aim[1] < self.maxs[0]) {
|
||||
// the hit is straight on so back the range up to the edge of their
|
||||
// bbox
|
||||
range -= self.enemy.maxs[0];
|
||||
} else {
|
||||
// this is a side hit so adjust the "right" value out to the edge of
|
||||
// their bbox
|
||||
if (aim[1] < 0)
|
||||
aim[1] = self.enemy.mins[0];
|
||||
else
|
||||
aim[1] = self.enemy.maxs[0];
|
||||
}
|
||||
|
||||
Math3D.VectorMA(self.s.origin, range, dir, point);
|
||||
|
||||
tr = GameBase.gi.trace(self.s.origin, null, null, point, self,
|
||||
Defines.MASK_SHOT);
|
||||
if (tr.fraction < 1) {
|
||||
if (0 == tr.ent.takedamage)
|
||||
return false;
|
||||
// if it will hit any client/monster then hit the one we wanted to
|
||||
// hit
|
||||
if ((tr.ent.svflags & Defines.SVF_MONSTER) != 0
|
||||
|| (tr.ent.client != null))
|
||||
tr.ent = self.enemy;
|
||||
}
|
||||
|
||||
Math3D.AngleVectors(self.s.angles, forward, right, up);
|
||||
Math3D.VectorMA(self.s.origin, range, forward, point);
|
||||
Math3D.VectorMA(point, aim[1], right, point);
|
||||
Math3D.VectorMA(point, aim[2], up, point);
|
||||
Math3D.VectorSubtract(point, self.enemy.s.origin, dir);
|
||||
|
||||
// do the damage
|
||||
GameCombat.T_Damage(tr.ent, self, self, dir, point, Globals.vec3_origin,
|
||||
damage, kick / 2, Defines.DAMAGE_NO_KNOCKBACK, Defines.MOD_HIT);
|
||||
|
||||
if (0 == (tr.ent.svflags & Defines.SVF_MONSTER)
|
||||
&& (null == tr.ent.client))
|
||||
return false;
|
||||
|
||||
// do our special form of knockback here
|
||||
Math3D.VectorMA(self.enemy.absmin, 0.5f, self.enemy.size, v);
|
||||
Math3D.VectorSubtract(v, point, v);
|
||||
Math3D.VectorNormalize(v);
|
||||
Math3D.VectorMA(self.enemy.velocity, kick, v, self.enemy.velocity);
|
||||
if (self.enemy.velocity[2] > 0)
|
||||
self.enemy.groundentity = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* =================
|
||||
* fire_lead
|
||||
*
|
||||
* This is an internal support routine used for bullet/pellet based weapons.
|
||||
* =================
|
||||
*/
|
||||
public static void fire_lead(edict_t self, float[] start, float[] aimdir,
|
||||
int damage, int kick, int te_impact, int hspread, int vspread,
|
||||
int mod) {
|
||||
trace_t tr;
|
||||
float[] dir = { 0, 0, 0 };
|
||||
float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
|
||||
float[] end = { 0, 0, 0 };
|
||||
float r;
|
||||
float u;
|
||||
float[] water_start = { 0, 0, 0 };
|
||||
boolean water = false;
|
||||
int content_mask = Defines.MASK_SHOT | Defines.MASK_WATER;
|
||||
|
||||
tr = GameBase.gi.trace(self.s.origin, null, null, start, self,
|
||||
Defines.MASK_SHOT);
|
||||
if (!(tr.fraction < 1.0)) {
|
||||
Math3D.vectoangles(aimdir, dir);
|
||||
Math3D.AngleVectors(dir, forward, right, up);
|
||||
|
||||
r = Lib.crandom() * hspread;
|
||||
u = Lib.crandom() * vspread;
|
||||
Math3D.VectorMA(start, 8192, forward, end);
|
||||
Math3D.VectorMA(end, r, right, end);
|
||||
Math3D.VectorMA(end, u, up, end);
|
||||
|
||||
if ((GameBase.gi.pointcontents.pointcontents(start) & Defines.MASK_WATER) != 0) {
|
||||
water = true;
|
||||
Math3D.VectorCopy(start, water_start);
|
||||
content_mask &= ~Defines.MASK_WATER;
|
||||
}
|
||||
|
||||
tr = GameBase.gi.trace(start, null, null, end, self, content_mask);
|
||||
|
||||
// see if we hit water
|
||||
if ((tr.contents & Defines.MASK_WATER) != 0) {
|
||||
int color;
|
||||
|
||||
water = true;
|
||||
Math3D.VectorCopy(tr.endpos, water_start);
|
||||
|
||||
if (!Math3D.VectorEquals(start, tr.endpos)) {
|
||||
if ((tr.contents & Defines.CONTENTS_WATER) != 0) {
|
||||
if (Lib.strcmp(tr.surface.name, "*brwater") == 0)
|
||||
color = Defines.SPLASH_BROWN_WATER;
|
||||
else
|
||||
color = Defines.SPLASH_BLUE_WATER;
|
||||
} else if ((tr.contents & Defines.CONTENTS_SLIME) != 0)
|
||||
color = Defines.SPLASH_SLIME;
|
||||
else if ((tr.contents & Defines.CONTENTS_LAVA) != 0)
|
||||
color = Defines.SPLASH_LAVA;
|
||||
else
|
||||
color = Defines.SPLASH_UNKNOWN;
|
||||
|
||||
if (color != Defines.SPLASH_UNKNOWN) {
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(Defines.TE_SPLASH);
|
||||
GameBase.gi.WriteByte(8);
|
||||
GameBase.gi.WritePosition(tr.endpos);
|
||||
GameBase.gi.WriteDir(tr.plane.normal);
|
||||
GameBase.gi.WriteByte(color);
|
||||
GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS);
|
||||
}
|
||||
|
||||
// change bullet's course when it enters water
|
||||
Math3D.VectorSubtract(end, start, dir);
|
||||
Math3D.vectoangles(dir, dir);
|
||||
Math3D.AngleVectors(dir, forward, right, up);
|
||||
r = Lib.crandom() * hspread * 2;
|
||||
u = Lib.crandom() * vspread * 2;
|
||||
Math3D.VectorMA(water_start, 8192, forward, end);
|
||||
Math3D.VectorMA(end, r, right, end);
|
||||
Math3D.VectorMA(end, u, up, end);
|
||||
}
|
||||
|
||||
// re-trace ignoring water this time
|
||||
tr = GameBase.gi.trace(water_start, null, null, end, self,
|
||||
Defines.MASK_SHOT);
|
||||
}
|
||||
}
|
||||
|
||||
// send gun puff / flash
|
||||
if (!((tr.surface != null) && 0 != (tr.surface.flags & Defines.SURF_SKY))) {
|
||||
if (tr.fraction < 1.0) {
|
||||
if (tr.ent.takedamage != 0) {
|
||||
GameCombat.T_Damage(tr.ent, self, self, aimdir, tr.endpos,
|
||||
tr.plane.normal, damage, kick,
|
||||
Defines.DAMAGE_BULLET, mod);
|
||||
} else {
|
||||
if (!"sky".equals(tr.surface.name)) {
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(te_impact);
|
||||
GameBase.gi.WritePosition(tr.endpos);
|
||||
GameBase.gi.WriteDir(tr.plane.normal);
|
||||
GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS);
|
||||
|
||||
if (self.client != null)
|
||||
PlayerWeapon.PlayerNoise(self, tr.endpos,
|
||||
Defines.PNOISE_IMPACT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if went through water, determine where the end and make a bubble
|
||||
// trail
|
||||
if (water) {
|
||||
float[] pos = { 0, 0, 0 };
|
||||
|
||||
Math3D.VectorSubtract(tr.endpos, water_start, dir);
|
||||
Math3D.VectorNormalize(dir);
|
||||
Math3D.VectorMA(tr.endpos, -2, dir, pos);
|
||||
if ((GameBase.gi.pointcontents.pointcontents(pos) & Defines.MASK_WATER) != 0)
|
||||
Math3D.VectorCopy(pos, tr.endpos);
|
||||
else
|
||||
tr = GameBase.gi.trace(pos, null, null, water_start, tr.ent,
|
||||
Defines.MASK_WATER);
|
||||
|
||||
Math3D.VectorAdd(water_start, tr.endpos, pos);
|
||||
Math3D.VectorScale(pos, 0.5f, pos);
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(Defines.TE_BUBBLETRAIL);
|
||||
GameBase.gi.WritePosition(water_start);
|
||||
GameBase.gi.WritePosition(tr.endpos);
|
||||
GameBase.gi.multicast(pos, Defines.MULTICAST_PVS);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ================= fire_bullet
|
||||
*
|
||||
* Fires a single round. Used for machinegun and chaingun. Would be fine for
|
||||
* pistols, rifles, etc.... =================
|
||||
*/
|
||||
public static void fire_bullet(edict_t self, float[] start, float[] aimdir,
|
||||
int damage, int kick, int hspread, int vspread, int mod) {
|
||||
fire_lead(self, start, aimdir, damage, kick, Defines.TE_GUNSHOT,
|
||||
hspread, vspread, mod);
|
||||
}
|
||||
|
||||
/*
|
||||
* =================
|
||||
* fire_shotgun
|
||||
*
|
||||
* Shoots shotgun pellets. Used by shotgun and super shotgun.
|
||||
* =================
|
||||
*/
|
||||
public static void fire_shotgun(edict_t self, float[] start,
|
||||
float[] aimdir, int damage, int kick, int hspread, int vspread,
|
||||
int count, int mod) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
fire_lead(self, start, aimdir, damage, kick, Defines.TE_SHOTGUN,
|
||||
hspread, vspread, mod);
|
||||
}
|
||||
|
||||
/*
|
||||
* =================
|
||||
* fire_blaster
|
||||
*
|
||||
* Fires a single blaster bolt. Used by the blaster and hyper blaster.
|
||||
* =================
|
||||
*/
|
||||
|
||||
public static void fire_blaster(edict_t self, float[] start, float[] dir,
|
||||
int damage, int speed, int effect, boolean hyper) {
|
||||
edict_t bolt;
|
||||
trace_t tr;
|
||||
|
||||
Math3D.VectorNormalize(dir);
|
||||
|
||||
bolt = GameUtil.G_Spawn();
|
||||
bolt.svflags = Defines.SVF_DEADMONSTER;
|
||||
// yes, I know it looks weird that projectiles are deadmonsters
|
||||
// what this means is that when prediction is used against the object
|
||||
// (blaster/hyperblaster shots), the player won't be solid clipped
|
||||
// against
|
||||
// the object. Right now trying to run into a firing hyperblaster
|
||||
// is very jerky since you are predicted 'against' the shots.
|
||||
Math3D.VectorCopy(start, bolt.s.origin);
|
||||
Math3D.VectorCopy(start, bolt.s.old_origin);
|
||||
Math3D.vectoangles(dir, bolt.s.angles);
|
||||
Math3D.VectorScale(dir, speed, bolt.velocity);
|
||||
bolt.movetype = Defines.MOVETYPE_FLYMISSILE;
|
||||
bolt.clipmask = Defines.MASK_SHOT;
|
||||
bolt.solid = Defines.SOLID_BBOX;
|
||||
bolt.s.effects |= effect;
|
||||
Math3D.VectorClear(bolt.mins);
|
||||
Math3D.VectorClear(bolt.maxs);
|
||||
bolt.s.modelindex = GameBase.gi
|
||||
.modelindex("models/objects/laser/tris.md2");
|
||||
bolt.s.sound = GameBase.gi.soundindex("misc/lasfly.wav");
|
||||
bolt.owner = self;
|
||||
bolt.touch = blaster_touch;
|
||||
bolt.nextthink = GameBase.level.time + 2;
|
||||
bolt.think = GameUtil.G_FreeEdictA;
|
||||
bolt.dmg = damage;
|
||||
bolt.classname = "bolt";
|
||||
if (hyper)
|
||||
bolt.spawnflags = 1;
|
||||
GameBase.gi.linkentity(bolt);
|
||||
|
||||
if (self.client != null)
|
||||
check_dodge(self, bolt.s.origin, dir, speed);
|
||||
|
||||
tr = GameBase.gi.trace(self.s.origin, null, null, bolt.s.origin, bolt,
|
||||
Defines.MASK_SHOT);
|
||||
if (tr.fraction < 1.0) {
|
||||
Math3D.VectorMA(bolt.s.origin, -10, dir, bolt.s.origin);
|
||||
bolt.touch.touch(bolt, tr.ent, GameBase.dummyplane, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void fire_grenade(edict_t self, float[] start,
|
||||
float[] aimdir, int damage, int speed, float timer,
|
||||
float damage_radius) {
|
||||
edict_t grenade;
|
||||
float[] dir = { 0, 0, 0 };
|
||||
float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
|
||||
|
||||
Math3D.vectoangles(aimdir, dir);
|
||||
Math3D.AngleVectors(dir, forward, right, up);
|
||||
|
||||
grenade = GameUtil.G_Spawn();
|
||||
Math3D.VectorCopy(start, grenade.s.origin);
|
||||
Math3D.VectorScale(aimdir, speed, grenade.velocity);
|
||||
Math3D.VectorMA(grenade.velocity, 200f + Lib.crandom() * 10.0f, up,
|
||||
grenade.velocity);
|
||||
Math3D.VectorMA(grenade.velocity, Lib.crandom() * 10.0f, right,
|
||||
grenade.velocity);
|
||||
Math3D.VectorSet(grenade.avelocity, 300, 300, 300);
|
||||
grenade.movetype = Defines.MOVETYPE_BOUNCE;
|
||||
grenade.clipmask = Defines.MASK_SHOT;
|
||||
grenade.solid = Defines.SOLID_BBOX;
|
||||
grenade.s.effects |= Defines.EF_GRENADE;
|
||||
Math3D.VectorClear(grenade.mins);
|
||||
Math3D.VectorClear(grenade.maxs);
|
||||
grenade.s.modelindex = GameBase.gi
|
||||
.modelindex("models/objects/grenade/tris.md2");
|
||||
grenade.owner = self;
|
||||
grenade.touch = Grenade_Touch;
|
||||
grenade.nextthink = GameBase.level.time + timer;
|
||||
grenade.think = Grenade_Explode;
|
||||
grenade.dmg = damage;
|
||||
grenade.dmg_radius = damage_radius;
|
||||
grenade.classname = "grenade";
|
||||
|
||||
GameBase.gi.linkentity(grenade);
|
||||
}
|
||||
|
||||
public static void fire_grenade2(edict_t self, float[] start,
|
||||
float[] aimdir, int damage, int speed, float timer,
|
||||
float damage_radius, boolean held) {
|
||||
edict_t grenade;
|
||||
float[] dir = { 0, 0, 0 };
|
||||
float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
|
||||
|
||||
Math3D.vectoangles(aimdir, dir);
|
||||
Math3D.AngleVectors(dir, forward, right, up);
|
||||
|
||||
grenade = GameUtil.G_Spawn();
|
||||
Math3D.VectorCopy(start, grenade.s.origin);
|
||||
Math3D.VectorScale(aimdir, speed, grenade.velocity);
|
||||
Math3D.VectorMA(grenade.velocity, 200f + Lib.crandom() * 10.0f, up,
|
||||
grenade.velocity);
|
||||
Math3D.VectorMA(grenade.velocity, Lib.crandom() * 10.0f, right,
|
||||
grenade.velocity);
|
||||
Math3D.VectorSet(grenade.avelocity, 300f, 300f, 300f);
|
||||
grenade.movetype = Defines.MOVETYPE_BOUNCE;
|
||||
grenade.clipmask = Defines.MASK_SHOT;
|
||||
grenade.solid = Defines.SOLID_BBOX;
|
||||
grenade.s.effects |= Defines.EF_GRENADE;
|
||||
Math3D.VectorClear(grenade.mins);
|
||||
Math3D.VectorClear(grenade.maxs);
|
||||
grenade.s.modelindex = GameBase.gi
|
||||
.modelindex("models/objects/grenade2/tris.md2");
|
||||
grenade.owner = self;
|
||||
grenade.touch = Grenade_Touch;
|
||||
grenade.nextthink = GameBase.level.time + timer;
|
||||
grenade.think = Grenade_Explode;
|
||||
grenade.dmg = damage;
|
||||
grenade.dmg_radius = damage_radius;
|
||||
grenade.classname = "hgrenade";
|
||||
if (held)
|
||||
grenade.spawnflags = 3;
|
||||
else
|
||||
grenade.spawnflags = 1;
|
||||
grenade.s.sound = GameBase.gi.soundindex("weapons/hgrenc1b.wav");
|
||||
|
||||
if (timer <= 0.0)
|
||||
Grenade_Explode.think(grenade);
|
||||
else {
|
||||
GameBase.gi.sound(self, Defines.CHAN_WEAPON, GameBase.gi
|
||||
.soundindex("weapons/hgrent1a.wav"), 1, Defines.ATTN_NORM,
|
||||
0);
|
||||
GameBase.gi.linkentity(grenade);
|
||||
}
|
||||
}
|
||||
|
||||
public static void fire_rocket(edict_t self, float[] start, float[] dir,
|
||||
int damage, int speed, float damage_radius, int radius_damage) {
|
||||
edict_t rocket;
|
||||
|
||||
rocket = GameUtil.G_Spawn();
|
||||
Math3D.VectorCopy(start, rocket.s.origin);
|
||||
Math3D.VectorCopy(dir, rocket.movedir);
|
||||
Math3D.vectoangles(dir, rocket.s.angles);
|
||||
Math3D.VectorScale(dir, speed, rocket.velocity);
|
||||
rocket.movetype = Defines.MOVETYPE_FLYMISSILE;
|
||||
rocket.clipmask = Defines.MASK_SHOT;
|
||||
rocket.solid = Defines.SOLID_BBOX;
|
||||
rocket.s.effects |= Defines.EF_ROCKET;
|
||||
Math3D.VectorClear(rocket.mins);
|
||||
Math3D.VectorClear(rocket.maxs);
|
||||
rocket.s.modelindex = GameBase.gi
|
||||
.modelindex("models/objects/rocket/tris.md2");
|
||||
rocket.owner = self;
|
||||
rocket.touch = rocket_touch;
|
||||
rocket.nextthink = GameBase.level.time + 8000 / speed;
|
||||
rocket.think = GameUtil.G_FreeEdictA;
|
||||
rocket.dmg = damage;
|
||||
rocket.radius_dmg = radius_damage;
|
||||
rocket.dmg_radius = damage_radius;
|
||||
rocket.s.sound = GameBase.gi.soundindex("weapons/rockfly.wav");
|
||||
rocket.classname = "rocket";
|
||||
|
||||
if (self.client != null)
|
||||
check_dodge(self, rocket.s.origin, dir, speed);
|
||||
|
||||
GameBase.gi.linkentity(rocket);
|
||||
}
|
||||
|
||||
/*
|
||||
* =================
|
||||
* fire_rail
|
||||
* =================
|
||||
*/
|
||||
public static void fire_rail(edict_t self, float[] start, float[] aimdir,
|
||||
int damage, int kick) {
|
||||
float[] from = { 0, 0, 0 };
|
||||
float[] end = { 0, 0, 0 };
|
||||
trace_t tr = null;
|
||||
edict_t ignore;
|
||||
int mask;
|
||||
boolean water;
|
||||
|
||||
Math3D.VectorMA(start, 8192f, aimdir, end);
|
||||
Math3D.VectorCopy(start, from);
|
||||
ignore = self;
|
||||
water = false;
|
||||
mask = Defines.MASK_SHOT | Defines.CONTENTS_SLIME
|
||||
| Defines.CONTENTS_LAVA;
|
||||
while (ignore != null) {
|
||||
tr = GameBase.gi.trace(from, null, null, end, ignore, mask);
|
||||
|
||||
if ((tr.contents & (Defines.CONTENTS_SLIME | Defines.CONTENTS_LAVA)) != 0) {
|
||||
mask &= ~(Defines.CONTENTS_SLIME | Defines.CONTENTS_LAVA);
|
||||
water = true;
|
||||
} else {
|
||||
//ZOID--added so rail goes through SOLID_BBOX entities (gibs,
|
||||
// etc)
|
||||
if ((tr.ent.svflags & Defines.SVF_MONSTER) != 0
|
||||
|| (tr.ent.client != null)
|
||||
|| (tr.ent.solid == Defines.SOLID_BBOX))
|
||||
ignore = tr.ent;
|
||||
else
|
||||
ignore = null;
|
||||
|
||||
if ((tr.ent != self) && (tr.ent.takedamage != 0))
|
||||
GameCombat.T_Damage(tr.ent, self, self, aimdir, tr.endpos,
|
||||
tr.plane.normal, damage, kick, 0,
|
||||
Defines.MOD_RAILGUN);
|
||||
}
|
||||
|
||||
Math3D.VectorCopy(tr.endpos, from);
|
||||
}
|
||||
|
||||
// send gun puff / flash
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(Defines.TE_RAILTRAIL);
|
||||
GameBase.gi.WritePosition(start);
|
||||
GameBase.gi.WritePosition(tr.endpos);
|
||||
GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PHS);
|
||||
// gi.multicast (start, MULTICAST_PHS);
|
||||
if (water) {
|
||||
GameBase.gi.WriteByte(Defines.svc_temp_entity);
|
||||
GameBase.gi.WriteByte(Defines.TE_RAILTRAIL);
|
||||
GameBase.gi.WritePosition(start);
|
||||
GameBase.gi.WritePosition(tr.endpos);
|
||||
GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PHS);
|
||||
}
|
||||
|
||||
if (self.client != null)
|
||||
PlayerWeapon.PlayerNoise(self, tr.endpos, Defines.PNOISE_IMPACT);
|
||||
}
|
||||
|
||||
public static void fire_bfg(edict_t self, float[] start, float[] dir,
|
||||
int damage, int speed, float damage_radius) {
|
||||
edict_t bfg;
|
||||
|
||||
bfg = GameUtil.G_Spawn();
|
||||
Math3D.VectorCopy(start, bfg.s.origin);
|
||||
Math3D.VectorCopy(dir, bfg.movedir);
|
||||
Math3D.vectoangles(dir, bfg.s.angles);
|
||||
Math3D.VectorScale(dir, speed, bfg.velocity);
|
||||
bfg.movetype = Defines.MOVETYPE_FLYMISSILE;
|
||||
bfg.clipmask = Defines.MASK_SHOT;
|
||||
bfg.solid = Defines.SOLID_BBOX;
|
||||
bfg.s.effects |= Defines.EF_BFG | Defines.EF_ANIM_ALLFAST;
|
||||
Math3D.VectorClear(bfg.mins);
|
||||
Math3D.VectorClear(bfg.maxs);
|
||||
bfg.s.modelindex = GameBase.gi.modelindex("sprites/s_bfg1.sp2");
|
||||
bfg.owner = self;
|
||||
bfg.touch = bfg_touch;
|
||||
bfg.nextthink = GameBase.level.time + 8000 / speed;
|
||||
bfg.think = GameUtil.G_FreeEdictA;
|
||||
bfg.radius_dmg = damage;
|
||||
bfg.dmg_radius = damage_radius;
|
||||
bfg.classname = "bfg blast";
|
||||
bfg.s.sound = GameBase.gi.soundindex("weapons/bfg__l1a.wav");
|
||||
|
||||
bfg.think = bfg_think;
|
||||
bfg.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
bfg.teammaster = bfg;
|
||||
bfg.teamchain = null;
|
||||
|
||||
if (self.client != null)
|
||||
check_dodge(self, bfg.s.origin, dir, speed);
|
||||
|
||||
GameBase.gi.linkentity(bfg);
|
||||
}
|
||||
}
|
||||
161
src/main/java/lwjake2/game/Info.java
Normal file
161
src/main/java/lwjake2/game/Info.java
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.qcommon.Com;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class Info {
|
||||
|
||||
/**
|
||||
* Returns a value for a key from an info string.
|
||||
*/
|
||||
public static String Info_ValueForKey(String s, String key) {
|
||||
|
||||
StringTokenizer tk = new StringTokenizer(s, "\\");
|
||||
|
||||
while (tk.hasMoreTokens()) {
|
||||
String key1 = tk.nextToken();
|
||||
|
||||
if (!tk.hasMoreTokens()) {
|
||||
Com.Printf("MISSING VALUE\n");
|
||||
return s;
|
||||
}
|
||||
String value1 = tk.nextToken();
|
||||
|
||||
if (key.equals(key1))
|
||||
return value1;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value for a key in the user info string.
|
||||
*/
|
||||
public static String Info_SetValueForKey(String s, String key, String value) {
|
||||
|
||||
if (value == null || value.length() == 0)
|
||||
return s;
|
||||
|
||||
if (key.indexOf('\\') != -1 || value.indexOf('\\') != -1) {
|
||||
Com.Printf("Can't use keys or values with a \\\n");
|
||||
return s;
|
||||
}
|
||||
|
||||
if (key.indexOf(';') != -1) {
|
||||
Com.Printf("Can't use keys or values with a semicolon\n");
|
||||
return s;
|
||||
}
|
||||
|
||||
if (key.indexOf('"') != -1 || value.indexOf('"') != -1) {
|
||||
Com.Printf("Can't use keys or values with a \"\n");
|
||||
return s;
|
||||
}
|
||||
|
||||
if (key.length() > Defines.MAX_INFO_KEY - 1
|
||||
|| value.length() > Defines.MAX_INFO_KEY - 1) {
|
||||
Com.Printf("Keys and values must be < 64 characters.\n");
|
||||
return s;
|
||||
}
|
||||
|
||||
StringBuffer sb = new StringBuffer(Info_RemoveKey(s, key));
|
||||
|
||||
if (sb.length() + 2 + key.length() + value.length() > Defines.MAX_INFO_STRING) {
|
||||
|
||||
Com.Printf("Info string length exceeded\n");
|
||||
return s;
|
||||
}
|
||||
|
||||
sb.append('\\').append(key).append('\\').append(value);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a key and value from an info string.
|
||||
*/
|
||||
public static String Info_RemoveKey(String s, String key) {
|
||||
|
||||
StringBuffer sb = new StringBuffer(512);
|
||||
|
||||
if (key.indexOf('\\') != -1) {
|
||||
Com.Printf("Can't use a key with a \\\n");
|
||||
return s;
|
||||
}
|
||||
|
||||
StringTokenizer tk = new StringTokenizer(s, "\\");
|
||||
|
||||
while (tk.hasMoreTokens()) {
|
||||
String key1 = tk.nextToken();
|
||||
|
||||
if (!tk.hasMoreTokens()) {
|
||||
Com.Printf("MISSING VALUE\n");
|
||||
return s;
|
||||
}
|
||||
String value1 = tk.nextToken();
|
||||
|
||||
if (!key.equals(key1))
|
||||
sb.append('\\').append(key1).append('\\').append(value1);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Some characters are illegal in info strings because they can mess up the
|
||||
* server's parsing.
|
||||
*/
|
||||
public static boolean Info_Validate(String s) {
|
||||
return !((s.indexOf('"') != -1) || (s.indexOf(';') != -1));
|
||||
}
|
||||
|
||||
private static String fillspaces = " ";
|
||||
|
||||
public static void Print(String s) {
|
||||
|
||||
StringBuffer sb = new StringBuffer(512);
|
||||
StringTokenizer tk = new StringTokenizer(s, "\\");
|
||||
|
||||
while (tk.hasMoreTokens()) {
|
||||
|
||||
String key1 = tk.nextToken();
|
||||
|
||||
if (!tk.hasMoreTokens()) {
|
||||
Com.Printf("MISSING VALUE\n");
|
||||
return;
|
||||
}
|
||||
|
||||
String value1 = tk.nextToken();
|
||||
|
||||
sb.append(key1);
|
||||
|
||||
int len = key1.length();
|
||||
|
||||
if (len < 20) {
|
||||
sb.append(fillspaces.substring(len));
|
||||
}
|
||||
sb.append('=').append(value1).append('\n');
|
||||
}
|
||||
Com.Printf(sb.toString());
|
||||
}
|
||||
}
|
||||
24
src/main/java/lwjake2/game/ItemDropAdapter.java
Normal file
24
src/main/java/lwjake2/game/ItemDropAdapter.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public abstract class ItemDropAdapter extends SuperAdapter {
|
||||
public void drop(edict_t ent, gitem_t item) {
|
||||
}
|
||||
}
|
||||
24
src/main/java/lwjake2/game/ItemUseAdapter.java
Normal file
24
src/main/java/lwjake2/game/ItemUseAdapter.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public abstract class ItemUseAdapter extends SuperAdapter {
|
||||
public void use(edict_t ent, gitem_t item) {
|
||||
}
|
||||
}
|
||||
357
src/main/java/lwjake2/game/Monster.java
Normal file
357
src/main/java/lwjake2/game/Monster.java
Normal file
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.client.M;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
public class Monster {
|
||||
|
||||
// FIXME monsters should call these with a totally accurate direction
|
||||
// and we can mess it up based on skill. Spread should be for normal
|
||||
// and we can tighten or loosen based on skill. We could muck with
|
||||
// the damages too, but I'm not sure that's such a good idea.
|
||||
public static void monster_fire_bullet(edict_t self, float[] start,
|
||||
float[] dir, int damage, int kick, int hspread, int vspread,
|
||||
int flashtype) {
|
||||
GameWeapon.fire_bullet(self, start, dir, damage, kick, hspread, vspread,
|
||||
Defines.MOD_UNKNOWN);
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
|
||||
GameBase.gi.WriteShort(self.index);
|
||||
GameBase.gi.WriteByte(flashtype);
|
||||
GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
|
||||
}
|
||||
|
||||
/** The Moster fires the shotgun. */
|
||||
public static void monster_fire_shotgun(edict_t self, float[] start,
|
||||
float[] aimdir, int damage, int kick, int hspread, int vspread,
|
||||
int count, int flashtype) {
|
||||
GameWeapon.fire_shotgun(self, start, aimdir, damage, kick, hspread, vspread,
|
||||
count, Defines.MOD_UNKNOWN);
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
|
||||
GameBase.gi.WriteShort(self.index);
|
||||
GameBase.gi.WriteByte(flashtype);
|
||||
GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
|
||||
}
|
||||
|
||||
/** The Moster fires the blaster. */
|
||||
public static void monster_fire_blaster(edict_t self, float[] start,
|
||||
float[] dir, int damage, int speed, int flashtype, int effect) {
|
||||
GameWeapon.fire_blaster(self, start, dir, damage, speed, effect, false);
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
|
||||
GameBase.gi.WriteShort(self.index);
|
||||
GameBase.gi.WriteByte(flashtype);
|
||||
GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
|
||||
}
|
||||
|
||||
/** The Moster fires the grenade. */
|
||||
public static void monster_fire_grenade(edict_t self, float[] start,
|
||||
float[] aimdir, int damage, int speed, int flashtype) {
|
||||
GameWeapon
|
||||
.fire_grenade(self, start, aimdir, damage, speed, 2.5f,
|
||||
damage + 40);
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
|
||||
GameBase.gi.WriteShort(self.index);
|
||||
GameBase.gi.WriteByte(flashtype);
|
||||
GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
|
||||
}
|
||||
|
||||
/** The Moster fires the rocket. */
|
||||
public static void monster_fire_rocket(edict_t self, float[] start,
|
||||
float[] dir, int damage, int speed, int flashtype) {
|
||||
GameWeapon.fire_rocket(self, start, dir, damage, speed, damage + 20, damage);
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
|
||||
GameBase.gi.WriteShort(self.index);
|
||||
GameBase.gi.WriteByte(flashtype);
|
||||
GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
|
||||
}
|
||||
|
||||
/** The Moster fires the railgun. */
|
||||
public static void monster_fire_railgun(edict_t self, float[] start,
|
||||
float[] aimdir, int damage, int kick, int flashtype) {
|
||||
GameWeapon.fire_rail(self, start, aimdir, damage, kick);
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
|
||||
GameBase.gi.WriteShort(self.index);
|
||||
GameBase.gi.WriteByte(flashtype);
|
||||
GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
|
||||
}
|
||||
|
||||
/** The Moster fires the bfg. */
|
||||
public static void monster_fire_bfg(edict_t self, float[] start,
|
||||
float[] aimdir, int damage, int speed, int kick,
|
||||
float damage_radius, int flashtype) {
|
||||
GameWeapon.fire_bfg(self, start, aimdir, damage, speed, damage_radius);
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
|
||||
GameBase.gi.WriteShort(self.index);
|
||||
GameBase.gi.WriteByte(flashtype);
|
||||
GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
|
||||
}
|
||||
|
||||
/*
|
||||
* ================ monster_death_use
|
||||
*
|
||||
* When a monster dies, it fires all of its targets with the current enemy
|
||||
* as activator. ================
|
||||
*/
|
||||
public static void monster_death_use(edict_t self) {
|
||||
self.flags &= ~(Defines.FL_FLY | Defines.FL_SWIM);
|
||||
self.monsterinfo.aiflags &= Defines.AI_GOOD_GUY;
|
||||
|
||||
if (self.item != null) {
|
||||
GameItems.Drop_Item(self, self.item);
|
||||
self.item = null;
|
||||
}
|
||||
|
||||
if (self.deathtarget != null)
|
||||
self.target = self.deathtarget;
|
||||
|
||||
if (self.target == null)
|
||||
return;
|
||||
|
||||
GameUtil.G_UseTargets(self, self.enemy);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
public static boolean monster_start(edict_t self) {
|
||||
if (GameBase.deathmatch.value != 0) {
|
||||
GameUtil.G_FreeEdict(self);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((self.spawnflags & 4) != 0
|
||||
&& 0 == (self.monsterinfo.aiflags & Defines.AI_GOOD_GUY)) {
|
||||
self.spawnflags &= ~4;
|
||||
self.spawnflags |= 1;
|
||||
// gi.dprintf("fixed spawnflags on %s at %s\n", self.classname,
|
||||
// vtos(self.s.origin));
|
||||
}
|
||||
|
||||
if (0 == (self.monsterinfo.aiflags & Defines.AI_GOOD_GUY))
|
||||
GameBase.level.total_monsters++;
|
||||
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
self.svflags |= Defines.SVF_MONSTER;
|
||||
self.s.renderfx |= Defines.RF_FRAMELERP;
|
||||
self.takedamage = Defines.DAMAGE_AIM;
|
||||
self.air_finished = GameBase.level.time + 12;
|
||||
self.use = GameUtil.monster_use;
|
||||
self.max_health = self.health;
|
||||
self.clipmask = Defines.MASK_MONSTERSOLID;
|
||||
|
||||
self.s.skinnum = 0;
|
||||
self.deadflag = Defines.DEAD_NO;
|
||||
self.svflags &= ~Defines.SVF_DEADMONSTER;
|
||||
|
||||
if (null == self.monsterinfo.checkattack)
|
||||
self.monsterinfo.checkattack = GameUtil.M_CheckAttack;
|
||||
Math3D.VectorCopy(self.s.origin, self.s.old_origin);
|
||||
|
||||
if (GameBase.st.item != null && GameBase.st.item.length() > 0) {
|
||||
self.item = GameItems.FindItemByClassname(GameBase.st.item);
|
||||
if (self.item == null)
|
||||
GameBase.gi.dprintf("monster_start:" + self.classname + " at "
|
||||
+ Lib.vtos(self.s.origin) + " has bad item: "
|
||||
+ GameBase.st.item + "\n");
|
||||
}
|
||||
|
||||
// randomize what frame they start on
|
||||
if (self.monsterinfo.currentmove != null)
|
||||
self.s.frame = self.monsterinfo.currentmove.firstframe
|
||||
+ (Lib.rand() % (self.monsterinfo.currentmove.lastframe
|
||||
- self.monsterinfo.currentmove.firstframe + 1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void monster_start_go(edict_t self) {
|
||||
|
||||
float[] v = { 0, 0, 0 };
|
||||
|
||||
if (self.health <= 0)
|
||||
return;
|
||||
|
||||
// check for target to combat_point and change to combattarget
|
||||
if (self.target != null) {
|
||||
boolean notcombat;
|
||||
boolean fixup;
|
||||
edict_t target = null;
|
||||
notcombat = false;
|
||||
fixup = false;
|
||||
/*
|
||||
* if (true) { Com.Printf("all entities:\n");
|
||||
*
|
||||
* for (int n = 0; n < Game.globals.num_edicts; n++) { edict_t ent =
|
||||
* GameBase.g_edicts[n]; Com.Printf( "|%4i | %25s
|
||||
* |%8.2f|%8.2f|%8.2f||%8.2f|%8.2f|%8.2f||%8.2f|%8.2f|%8.2f|\n", new
|
||||
* Vargs().add(n).add(ent.classname).
|
||||
* add(ent.s.origin[0]).add(ent.s.origin[1]).add(ent.s.origin[2])
|
||||
* .add(ent.mins[0]).add(ent.mins[1]).add(ent.mins[2])
|
||||
* .add(ent.maxs[0]).add(ent.maxs[1]).add(ent.maxs[2])); }
|
||||
* sleep(10); }
|
||||
*/
|
||||
|
||||
EdictIterator edit = null;
|
||||
|
||||
while ((edit = GameBase.G_Find(edit, GameBase.findByTarget,
|
||||
self.target)) != null) {
|
||||
target = edit.o;
|
||||
if (Lib.strcmp(target.classname, "point_combat") == 0) {
|
||||
self.combattarget = self.target;
|
||||
fixup = true;
|
||||
} else {
|
||||
notcombat = true;
|
||||
}
|
||||
}
|
||||
if (notcombat && self.combattarget != null)
|
||||
GameBase.gi.dprintf(self.classname + " at "
|
||||
+ Lib.vtos(self.s.origin)
|
||||
+ " has target with mixed types\n");
|
||||
if (fixup)
|
||||
self.target = null;
|
||||
}
|
||||
|
||||
// validate combattarget
|
||||
if (self.combattarget != null) {
|
||||
edict_t target = null;
|
||||
|
||||
EdictIterator edit = null;
|
||||
while ((edit = GameBase.G_Find(edit, GameBase.findByTarget,
|
||||
self.combattarget)) != null) {
|
||||
target = edit.o;
|
||||
|
||||
if (Lib.strcmp(target.classname, "point_combat") != 0) {
|
||||
GameBase.gi.dprintf(self.classname + " at "
|
||||
+ Lib.vtos(self.s.origin)
|
||||
+ " has bad combattarget " + self.combattarget
|
||||
+ " : " + target.classname + " at "
|
||||
+ Lib.vtos(target.s.origin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self.target != null) {
|
||||
self.goalentity = self.movetarget = GameBase
|
||||
.G_PickTarget(self.target);
|
||||
if (null == self.movetarget) {
|
||||
GameBase.gi
|
||||
.dprintf(self.classname + " can't find target "
|
||||
+ self.target + " at "
|
||||
+ Lib.vtos(self.s.origin) + "\n");
|
||||
self.target = null;
|
||||
self.monsterinfo.pausetime = 100000000;
|
||||
self.monsterinfo.stand.think(self);
|
||||
} else if (Lib.strcmp(self.movetarget.classname, "path_corner") == 0) {
|
||||
Math3D.VectorSubtract(self.goalentity.s.origin, self.s.origin,
|
||||
v);
|
||||
self.ideal_yaw = self.s.angles[Defines.YAW] = Math3D
|
||||
.vectoyaw(v);
|
||||
self.monsterinfo.walk.think(self);
|
||||
self.target = null;
|
||||
} else {
|
||||
self.goalentity = self.movetarget = null;
|
||||
self.monsterinfo.pausetime = 100000000;
|
||||
self.monsterinfo.stand.think(self);
|
||||
}
|
||||
} else {
|
||||
self.monsterinfo.pausetime = 100000000;
|
||||
self.monsterinfo.stand.think(self);
|
||||
}
|
||||
|
||||
self.think = Monster.monster_think;
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
}
|
||||
|
||||
public static EntThinkAdapter monster_think = new EntThinkAdapter() {
|
||||
public String getID() { return "monster_think";}
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
M.M_MoveFrame(self);
|
||||
if (self.linkcount != self.monsterinfo.linkcount) {
|
||||
self.monsterinfo.linkcount = self.linkcount;
|
||||
M.M_CheckGround(self);
|
||||
}
|
||||
M.M_CatagorizePosition(self);
|
||||
M.M_WorldEffects(self);
|
||||
M.M_SetEffects(self);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static EntThinkAdapter monster_triggered_spawn = new EntThinkAdapter() {
|
||||
public String getID() { return "monster_trigger_spawn";}
|
||||
public boolean think(edict_t self) {
|
||||
|
||||
self.s.origin[2] += 1;
|
||||
GameUtil.KillBox(self);
|
||||
|
||||
self.solid = Defines.SOLID_BBOX;
|
||||
self.movetype = Defines.MOVETYPE_STEP;
|
||||
self.svflags &= ~Defines.SVF_NOCLIENT;
|
||||
self.air_finished = GameBase.level.time + 12;
|
||||
GameBase.gi.linkentity(self);
|
||||
|
||||
Monster.monster_start_go(self);
|
||||
|
||||
if (self.enemy != null && 0 == (self.spawnflags & 1)
|
||||
&& 0 == (self.enemy.flags & Defines.FL_NOTARGET)) {
|
||||
GameUtil.FoundTarget(self);
|
||||
} else {
|
||||
self.enemy = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// we have a one frame delay here so we don't telefrag the guy who activated
|
||||
// us
|
||||
public static EntUseAdapter monster_triggered_spawn_use = new EntUseAdapter() {
|
||||
public String getID() { return "monster_trigger_spawn_use";}
|
||||
public void use(edict_t self, edict_t other, edict_t activator) {
|
||||
self.think = monster_triggered_spawn;
|
||||
self.nextthink = GameBase.level.time + Defines.FRAMETIME;
|
||||
if (activator.client != null)
|
||||
self.enemy = activator;
|
||||
self.use = GameUtil.monster_use;
|
||||
}
|
||||
};
|
||||
|
||||
public static EntThinkAdapter monster_triggered_start = new EntThinkAdapter() {
|
||||
public String getID() { return "monster_triggered_start";}
|
||||
public boolean think(edict_t self) {
|
||||
if (self.index == 312)
|
||||
Com.Printf("monster_triggered_start\n");
|
||||
self.solid = Defines.SOLID_NOT;
|
||||
self.movetype = Defines.MOVETYPE_NONE;
|
||||
self.svflags |= Defines.SVF_NOCLIENT;
|
||||
self.nextthink = 0;
|
||||
self.use = monster_triggered_spawn_use;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
1731
src/main/java/lwjake2/game/PlayerClient.java
Normal file
1731
src/main/java/lwjake2/game/PlayerClient.java
Normal file
File diff suppressed because it is too large
Load Diff
531
src/main/java/lwjake2/game/PlayerHud.java
Normal file
531
src/main/java/lwjake2/game/PlayerHud.java
Normal file
@@ -0,0 +1,531 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.Math3D;
|
||||
import lwjake2.util.Vargs;
|
||||
|
||||
public class PlayerHud {
|
||||
|
||||
/*
|
||||
* ======================================================================
|
||||
*
|
||||
* INTERMISSION
|
||||
*
|
||||
* ======================================================================
|
||||
*/
|
||||
|
||||
public static void MoveClientToIntermission(edict_t ent) {
|
||||
if (GameBase.deathmatch.value != 0 || GameBase.coop.value != 0)
|
||||
ent.client.showscores = true;
|
||||
Math3D.VectorCopy(GameBase.level.intermission_origin, ent.s.origin);
|
||||
ent.client.ps.pmove.origin[0] = (short) (GameBase.level.intermission_origin[0] * 8);
|
||||
ent.client.ps.pmove.origin[1] = (short) (GameBase.level.intermission_origin[1] * 8);
|
||||
ent.client.ps.pmove.origin[2] = (short) (GameBase.level.intermission_origin[2] * 8);
|
||||
Math3D.VectorCopy(GameBase.level.intermission_angle,
|
||||
ent.client.ps.viewangles);
|
||||
ent.client.ps.pmove.pm_type = Defines.PM_FREEZE;
|
||||
ent.client.ps.gunindex = 0;
|
||||
ent.client.ps.blend[3] = 0;
|
||||
ent.client.ps.rdflags &= ~Defines.RDF_UNDERWATER;
|
||||
|
||||
// clean up powerup info
|
||||
ent.client.quad_framenum = 0;
|
||||
ent.client.invincible_framenum = 0;
|
||||
ent.client.breather_framenum = 0;
|
||||
ent.client.enviro_framenum = 0;
|
||||
ent.client.grenade_blew_up = false;
|
||||
ent.client.grenade_time = 0;
|
||||
|
||||
ent.viewheight = 0;
|
||||
ent.s.modelindex = 0;
|
||||
ent.s.modelindex2 = 0;
|
||||
ent.s.modelindex3 = 0;
|
||||
ent.s.modelindex = 0;
|
||||
ent.s.effects = 0;
|
||||
ent.s.sound = 0;
|
||||
ent.solid = Defines.SOLID_NOT;
|
||||
|
||||
// add the layout
|
||||
|
||||
if (GameBase.deathmatch.value != 0 || GameBase.coop.value != 0) {
|
||||
DeathmatchScoreboardMessage(ent, null);
|
||||
GameBase.gi.unicast(ent, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void BeginIntermission(edict_t targ) {
|
||||
int i, n;
|
||||
edict_t ent, client;
|
||||
|
||||
if (GameBase.level.intermissiontime != 0)
|
||||
return; // already activated
|
||||
|
||||
GameBase.game.autosaved = false;
|
||||
|
||||
// respawn any dead clients
|
||||
for (i = 0; i < GameBase.maxclients.value; i++) {
|
||||
client = GameBase.g_edicts[1 + i];
|
||||
if (!client.inuse)
|
||||
continue;
|
||||
if (client.health <= 0)
|
||||
PlayerClient.respawn(client);
|
||||
}
|
||||
|
||||
GameBase.level.intermissiontime = GameBase.level.time;
|
||||
GameBase.level.changemap = targ.map;
|
||||
|
||||
if (GameBase.level.changemap.indexOf('*') > -1) {
|
||||
if (GameBase.coop.value != 0) {
|
||||
for (i = 0; i < GameBase.maxclients.value; i++) {
|
||||
client = GameBase.g_edicts[1 + i];
|
||||
if (!client.inuse)
|
||||
continue;
|
||||
// strip players of all keys between units
|
||||
for (n = 1; n < GameItemList.itemlist.length; n++) {
|
||||
// null pointer exception fixed. (RST)
|
||||
if (GameItemList.itemlist[n] != null)
|
||||
if ((GameItemList.itemlist[n].flags & Defines.IT_KEY) != 0)
|
||||
client.client.pers.inventory[n] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (0 == GameBase.deathmatch.value) {
|
||||
GameBase.level.exitintermission = true; // go immediately to the
|
||||
// next level
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GameBase.level.exitintermission = false;
|
||||
|
||||
// find an intermission spot
|
||||
ent = GameBase.G_FindEdict(null, GameBase.findByClass,
|
||||
"info_player_intermission");
|
||||
if (ent == null) { // the map creator forgot to put in an intermission
|
||||
// point...
|
||||
ent = GameBase.G_FindEdict(null, GameBase.findByClass,
|
||||
"info_player_start");
|
||||
if (ent == null)
|
||||
ent = GameBase.G_FindEdict(null, GameBase.findByClass,
|
||||
"info_player_deathmatch");
|
||||
} else { // chose one of four spots
|
||||
i = Lib.rand() & 3;
|
||||
EdictIterator es = null;
|
||||
|
||||
while (i-- > 0) {
|
||||
es = GameBase.G_Find(es, GameBase.findByClass,
|
||||
"info_player_intermission");
|
||||
|
||||
if (es == null) // wrap around the list
|
||||
continue;
|
||||
ent = es.o;
|
||||
}
|
||||
}
|
||||
|
||||
Math3D.VectorCopy(ent.s.origin, GameBase.level.intermission_origin);
|
||||
Math3D.VectorCopy(ent.s.angles, GameBase.level.intermission_angle);
|
||||
|
||||
// move all clients to the intermission point
|
||||
for (i = 0; i < GameBase.maxclients.value; i++) {
|
||||
client = GameBase.g_edicts[1 + i];
|
||||
if (!client.inuse)
|
||||
continue;
|
||||
MoveClientToIntermission(client);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ==================
|
||||
* DeathmatchScoreboardMessage
|
||||
* ==================
|
||||
*/
|
||||
public static void DeathmatchScoreboardMessage(edict_t ent, edict_t killer) {
|
||||
StringBuffer string = new StringBuffer(1400);
|
||||
|
||||
int i, j, k;
|
||||
int sorted[] = new int[Defines.MAX_CLIENTS];
|
||||
int sortedscores[] = new int[Defines.MAX_CLIENTS];
|
||||
int score, total;
|
||||
int x, y;
|
||||
gclient_t cl;
|
||||
edict_t cl_ent;
|
||||
String tag;
|
||||
|
||||
// sort the clients by score
|
||||
total = 0;
|
||||
for (i = 0; i < GameBase.game.maxclients; i++) {
|
||||
cl_ent = GameBase.g_edicts[1 + i];
|
||||
if (!cl_ent.inuse || GameBase.game.clients[i].resp.spectator)
|
||||
continue;
|
||||
score = GameBase.game.clients[i].resp.score;
|
||||
for (j = 0; j < total; j++) {
|
||||
if (score > sortedscores[j])
|
||||
break;
|
||||
}
|
||||
for (k = total; k > j; k--) {
|
||||
sorted[k] = sorted[k - 1];
|
||||
sortedscores[k] = sortedscores[k - 1];
|
||||
}
|
||||
sorted[j] = i;
|
||||
sortedscores[j] = score;
|
||||
total++;
|
||||
}
|
||||
|
||||
// print level name and exit rules
|
||||
|
||||
// add the clients in sorted order
|
||||
if (total > 12)
|
||||
total = 12;
|
||||
|
||||
for (i = 0; i < total; i++) {
|
||||
cl = GameBase.game.clients[sorted[i]];
|
||||
cl_ent = GameBase.g_edicts[1 + sorted[i]];
|
||||
|
||||
GameBase.gi.imageindex("i_fixme");
|
||||
x = (i >= 6) ? 160 : 0;
|
||||
y = 32 + 32 * (i % 6);
|
||||
|
||||
// add a dogtag
|
||||
if (cl_ent == ent)
|
||||
tag = "tag1";
|
||||
else if (cl_ent == killer)
|
||||
tag = "tag2";
|
||||
else
|
||||
tag = null;
|
||||
|
||||
if (tag != null) {
|
||||
string.append("xv ").append(x + 32).append(" yv ").append(y)
|
||||
.append(" picn ").append(tag);
|
||||
}
|
||||
|
||||
// send the layout
|
||||
string
|
||||
.append(" client ")
|
||||
.append(x)
|
||||
.append(" ")
|
||||
.append(y)
|
||||
.append(" ")
|
||||
.append(sorted[i])
|
||||
.append(" ")
|
||||
.append(cl.resp.score)
|
||||
.append(" ")
|
||||
.append(cl.ping)
|
||||
.append(" ")
|
||||
.append(
|
||||
(GameBase.level.framenum - cl.resp.enterframe) / 600);
|
||||
}
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_layout);
|
||||
GameBase.gi.WriteString(string.toString());
|
||||
}
|
||||
|
||||
/*
|
||||
* ==================
|
||||
* DeathmatchScoreboard
|
||||
*
|
||||
* Draw instead of help message. Note that it isn't that hard to overflow
|
||||
* the 1400 byte message limit!
|
||||
* ==================
|
||||
*/
|
||||
public static void DeathmatchScoreboard(edict_t ent) {
|
||||
DeathmatchScoreboardMessage(ent, ent.enemy);
|
||||
GameBase.gi.unicast(ent, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* ==================
|
||||
* Cmd_Score_f
|
||||
*
|
||||
* Display the scoreboard
|
||||
* ==================
|
||||
*/
|
||||
public static void Cmd_Score_f(edict_t ent) {
|
||||
ent.client.showinventory = false;
|
||||
ent.client.showhelp = false;
|
||||
|
||||
if (0 == GameBase.deathmatch.value && 0 == GameBase.coop.value)
|
||||
return;
|
||||
|
||||
if (ent.client.showscores) {
|
||||
ent.client.showscores = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ent.client.showscores = true;
|
||||
DeathmatchScoreboard(ent);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
|
||||
/*
|
||||
* ===============
|
||||
* G_SetStats
|
||||
* ===============
|
||||
*/
|
||||
public static void G_SetStats(edict_t ent) {
|
||||
gitem_t item;
|
||||
int index, cells = 0;
|
||||
int power_armor_type;
|
||||
|
||||
//
|
||||
// health
|
||||
//
|
||||
ent.client.ps.stats[Defines.STAT_HEALTH_ICON] = (short) GameBase.level.pic_health;
|
||||
ent.client.ps.stats[Defines.STAT_HEALTH] = (short) ent.health;
|
||||
|
||||
//
|
||||
// ammo
|
||||
//
|
||||
if (0 == ent.client.ammo_index /*
|
||||
* ||
|
||||
* !ent.client.pers.inventory[ent.client.ammo_index]
|
||||
*/
|
||||
) {
|
||||
ent.client.ps.stats[Defines.STAT_AMMO_ICON] = 0;
|
||||
ent.client.ps.stats[Defines.STAT_AMMO] = 0;
|
||||
} else {
|
||||
item = GameItemList.itemlist[ent.client.ammo_index];
|
||||
ent.client.ps.stats[Defines.STAT_AMMO_ICON] = (short) GameBase.gi
|
||||
.imageindex(item.icon);
|
||||
ent.client.ps.stats[Defines.STAT_AMMO] = (short) ent.client.pers.inventory[ent.client.ammo_index];
|
||||
}
|
||||
|
||||
//
|
||||
// armor
|
||||
//
|
||||
power_armor_type = GameItems.PowerArmorType(ent);
|
||||
if (power_armor_type != 0) {
|
||||
cells = ent.client.pers.inventory[GameItems.ITEM_INDEX(GameItems
|
||||
.FindItem("cells"))];
|
||||
if (cells == 0) { // ran out of cells for power armor
|
||||
ent.flags &= ~Defines.FL_POWER_ARMOR;
|
||||
GameBase.gi
|
||||
.sound(ent, Defines.CHAN_ITEM, GameBase.gi
|
||||
.soundindex("misc/power2.wav"), 1,
|
||||
Defines.ATTN_NORM, 0);
|
||||
power_armor_type = 0;
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
index = GameItems.ArmorIndex(ent);
|
||||
if (power_armor_type != 0
|
||||
&& (0 == index || 0 != (GameBase.level.framenum & 8))) { // flash
|
||||
// between
|
||||
// power
|
||||
// armor
|
||||
// and
|
||||
// other
|
||||
// armor
|
||||
// icon
|
||||
ent.client.ps.stats[Defines.STAT_ARMOR_ICON] = (short) GameBase.gi
|
||||
.imageindex("i_powershield");
|
||||
ent.client.ps.stats[Defines.STAT_ARMOR] = (short) cells;
|
||||
} else if (index != 0) {
|
||||
item = GameItems.GetItemByIndex(index);
|
||||
ent.client.ps.stats[Defines.STAT_ARMOR_ICON] = (short) GameBase.gi
|
||||
.imageindex(item.icon);
|
||||
ent.client.ps.stats[Defines.STAT_ARMOR] = (short) ent.client.pers.inventory[index];
|
||||
} else {
|
||||
ent.client.ps.stats[Defines.STAT_ARMOR_ICON] = 0;
|
||||
ent.client.ps.stats[Defines.STAT_ARMOR] = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// pickup message
|
||||
//
|
||||
if (GameBase.level.time > ent.client.pickup_msg_time) {
|
||||
ent.client.ps.stats[Defines.STAT_PICKUP_ICON] = 0;
|
||||
ent.client.ps.stats[Defines.STAT_PICKUP_STRING] = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// timers
|
||||
//
|
||||
if (ent.client.quad_framenum > GameBase.level.framenum) {
|
||||
ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi
|
||||
.imageindex("p_quad");
|
||||
ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.quad_framenum - GameBase.level.framenum) / 10);
|
||||
} else if (ent.client.invincible_framenum > GameBase.level.framenum) {
|
||||
ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi
|
||||
.imageindex("p_invulnerability");
|
||||
ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.invincible_framenum - GameBase.level.framenum) / 10);
|
||||
} else if (ent.client.enviro_framenum > GameBase.level.framenum) {
|
||||
ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi
|
||||
.imageindex("p_envirosuit");
|
||||
ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.enviro_framenum - GameBase.level.framenum) / 10);
|
||||
} else if (ent.client.breather_framenum > GameBase.level.framenum) {
|
||||
ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi
|
||||
.imageindex("p_rebreather");
|
||||
ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.breather_framenum - GameBase.level.framenum) / 10);
|
||||
} else {
|
||||
ent.client.ps.stats[Defines.STAT_TIMER_ICON] = 0;
|
||||
ent.client.ps.stats[Defines.STAT_TIMER] = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// selected item
|
||||
//
|
||||
// bugfix rst
|
||||
if (ent.client.pers.selected_item <= 0)
|
||||
ent.client.ps.stats[Defines.STAT_SELECTED_ICON] = 0;
|
||||
else
|
||||
ent.client.ps.stats[Defines.STAT_SELECTED_ICON] = (short) GameBase.gi
|
||||
.imageindex(GameItemList.itemlist[ent.client.pers.selected_item].icon);
|
||||
|
||||
ent.client.ps.stats[Defines.STAT_SELECTED_ITEM] = (short) ent.client.pers.selected_item;
|
||||
|
||||
//
|
||||
// layouts
|
||||
//
|
||||
ent.client.ps.stats[Defines.STAT_LAYOUTS] = 0;
|
||||
|
||||
if (GameBase.deathmatch.value != 0) {
|
||||
if (ent.client.pers.health <= 0
|
||||
|| GameBase.level.intermissiontime != 0
|
||||
|| ent.client.showscores)
|
||||
ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 1;
|
||||
if (ent.client.showinventory && ent.client.pers.health > 0)
|
||||
ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 2;
|
||||
} else {
|
||||
if (ent.client.showscores || ent.client.showhelp)
|
||||
ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 1;
|
||||
if (ent.client.showinventory && ent.client.pers.health > 0)
|
||||
ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 2;
|
||||
}
|
||||
|
||||
//
|
||||
// frags
|
||||
//
|
||||
ent.client.ps.stats[Defines.STAT_FRAGS] = (short) ent.client.resp.score;
|
||||
|
||||
//
|
||||
// help icon / current weapon if not shown
|
||||
//
|
||||
if (ent.client.pers.helpchanged != 0
|
||||
&& (GameBase.level.framenum & 8) != 0)
|
||||
ent.client.ps.stats[Defines.STAT_HELPICON] = (short) GameBase.gi
|
||||
.imageindex("i_help");
|
||||
else if ((ent.client.pers.hand == Defines.CENTER_HANDED || ent.client.ps.fov > 91)
|
||||
&& ent.client.pers.weapon != null)
|
||||
ent.client.ps.stats[Defines.STAT_HELPICON] = (short) GameBase.gi
|
||||
.imageindex(ent.client.pers.weapon.icon);
|
||||
else
|
||||
ent.client.ps.stats[Defines.STAT_HELPICON] = 0;
|
||||
|
||||
ent.client.ps.stats[Defines.STAT_SPECTATOR] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===============
|
||||
* G_CheckChaseStats
|
||||
* ===============
|
||||
*/
|
||||
public static void G_CheckChaseStats(edict_t ent) {
|
||||
int i;
|
||||
gclient_t cl;
|
||||
|
||||
for (i = 1; i <= GameBase.maxclients.value; i++) {
|
||||
cl = GameBase.g_edicts[i].client;
|
||||
if (!GameBase.g_edicts[i].inuse || cl.chase_target != ent)
|
||||
continue;
|
||||
//memcpy(cl.ps.stats, ent.client.ps.stats, sizeof(cl.ps.stats));
|
||||
System.arraycopy(ent.client.ps.stats, 0, cl.ps.stats, 0,
|
||||
Defines.MAX_STATS);
|
||||
|
||||
G_SetSpectatorStats(GameBase.g_edicts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ===============
|
||||
* G_SetSpectatorStats
|
||||
* ===============
|
||||
*/
|
||||
public static void G_SetSpectatorStats(edict_t ent) {
|
||||
gclient_t cl = ent.client;
|
||||
|
||||
if (null == cl.chase_target)
|
||||
G_SetStats(ent);
|
||||
|
||||
cl.ps.stats[Defines.STAT_SPECTATOR] = 1;
|
||||
|
||||
// layouts are independant in spectator
|
||||
cl.ps.stats[Defines.STAT_LAYOUTS] = 0;
|
||||
if (cl.pers.health <= 0 || GameBase.level.intermissiontime != 0
|
||||
|| cl.showscores)
|
||||
cl.ps.stats[Defines.STAT_LAYOUTS] |= 1;
|
||||
if (cl.showinventory && cl.pers.health > 0)
|
||||
cl.ps.stats[Defines.STAT_LAYOUTS] |= 2;
|
||||
|
||||
if (cl.chase_target != null && cl.chase_target.inuse)
|
||||
//cl.ps.stats[STAT_CHASE] = (short) (CS_PLAYERSKINS +
|
||||
// (cl.chase_target - g_edicts) - 1);
|
||||
cl.ps.stats[Defines.STAT_CHASE] = (short) (Defines.CS_PLAYERSKINS
|
||||
+ cl.chase_target.index - 1);
|
||||
else
|
||||
cl.ps.stats[Defines.STAT_CHASE] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* HelpComputer. Draws the help computer.
|
||||
*/
|
||||
public static void HelpComputer(edict_t ent) {
|
||||
StringBuffer sb = new StringBuffer(256);
|
||||
String sk;
|
||||
|
||||
if (GameBase.skill.value == 0)
|
||||
sk = "easy";
|
||||
else if (GameBase.skill.value == 1)
|
||||
sk = "medium";
|
||||
else if (GameBase.skill.value == 2)
|
||||
sk = "hard";
|
||||
else
|
||||
sk = "hard+";
|
||||
|
||||
// send the layout
|
||||
sb.append("xv 32 yv 8 picn help "); // background
|
||||
sb.append("xv 202 yv 12 string2 \"").append(sk).append("\" "); // skill
|
||||
sb.append("xv 0 yv 24 cstring2 \"").append(GameBase.level.level_name)
|
||||
.append("\" "); // level name
|
||||
sb.append("xv 0 yv 54 cstring2 \"").append(GameBase.game.helpmessage1)
|
||||
.append("\" "); // help 1
|
||||
sb.append("xv 0 yv 110 cstring2 \"").append(GameBase.game.helpmessage2)
|
||||
.append("\" "); // help 2
|
||||
sb.append("xv 50 yv 164 string2 \" kills goals secrets\" ");
|
||||
sb.append("xv 50 yv 172 string2 \"");
|
||||
sb.append(Com.sprintf("%3i/%3i %i/%i %i/%i\" ", new Vargs(6)
|
||||
.add(GameBase.level.killed_monsters).add(
|
||||
GameBase.level.total_monsters).add(
|
||||
GameBase.level.found_goals).add(
|
||||
GameBase.level.total_goals).add(
|
||||
GameBase.level.found_secrets).add(
|
||||
GameBase.level.total_secrets)));
|
||||
|
||||
GameBase.gi.WriteByte(Defines.svc_layout);
|
||||
GameBase.gi.WriteString(sb.toString());
|
||||
GameBase.gi.unicast(ent, true);
|
||||
}
|
||||
}
|
||||
144
src/main/java/lwjake2/game/PlayerTrail.java
Normal file
144
src/main/java/lwjake2/game/PlayerTrail.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
public class PlayerTrail {
|
||||
|
||||
/*
|
||||
* ==============================================================================
|
||||
*
|
||||
* PLAYER TRAIL
|
||||
*
|
||||
* ==============================================================================
|
||||
*
|
||||
* This is a circular list containing the a list of points of where the
|
||||
* player has been recently. It is used by monsters for pursuit.
|
||||
*
|
||||
* .origin the spot .owner forward link .aiment backward link
|
||||
*/
|
||||
|
||||
static int TRAIL_LENGTH = 8;
|
||||
|
||||
static edict_t trail[] = new edict_t[TRAIL_LENGTH];
|
||||
|
||||
static int trail_head;
|
||||
|
||||
static boolean trail_active = false;
|
||||
static {
|
||||
//TODO: potential error
|
||||
for (int n = 0; n < TRAIL_LENGTH; n++)
|
||||
trail[n] = new edict_t(n);
|
||||
}
|
||||
|
||||
static int NEXT(int n) {
|
||||
return (n + 1) % PlayerTrail.TRAIL_LENGTH;
|
||||
}
|
||||
|
||||
static int PREV(int n) {
|
||||
return (n + PlayerTrail.TRAIL_LENGTH - 1) % PlayerTrail.TRAIL_LENGTH;
|
||||
}
|
||||
|
||||
static void Init() {
|
||||
|
||||
// FIXME || coop
|
||||
if (GameBase.deathmatch.value != 0)
|
||||
return;
|
||||
|
||||
for (int n = 0; n < PlayerTrail.TRAIL_LENGTH; n++) {
|
||||
PlayerTrail.trail[n] = GameUtil.G_Spawn();
|
||||
PlayerTrail.trail[n].classname = "player_trail";
|
||||
}
|
||||
|
||||
trail_head = 0;
|
||||
trail_active = true;
|
||||
}
|
||||
|
||||
static void Add(float[] spot) {
|
||||
float[] temp = { 0, 0, 0 };
|
||||
|
||||
if (!trail_active)
|
||||
return;
|
||||
|
||||
Math3D.VectorCopy(spot, PlayerTrail.trail[trail_head].s.origin);
|
||||
|
||||
PlayerTrail.trail[trail_head].timestamp = GameBase.level.time;
|
||||
|
||||
Math3D.VectorSubtract(spot,
|
||||
PlayerTrail.trail[PREV(trail_head)].s.origin, temp);
|
||||
PlayerTrail.trail[trail_head].s.angles[1] = Math3D.vectoyaw(temp);
|
||||
|
||||
trail_head = NEXT(trail_head);
|
||||
}
|
||||
|
||||
static void New(float[] spot) {
|
||||
if (!trail_active)
|
||||
return;
|
||||
|
||||
Init();
|
||||
Add(spot);
|
||||
}
|
||||
|
||||
static edict_t PickFirst(edict_t self) {
|
||||
|
||||
if (!trail_active)
|
||||
return null;
|
||||
|
||||
int marker = trail_head;
|
||||
|
||||
for (int n = PlayerTrail.TRAIL_LENGTH; n > 0; n--) {
|
||||
if (PlayerTrail.trail[marker].timestamp <= self.monsterinfo.trail_time)
|
||||
marker = NEXT(marker);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (GameUtil.visible(self, PlayerTrail.trail[marker])) {
|
||||
return PlayerTrail.trail[marker];
|
||||
}
|
||||
|
||||
if (GameUtil.visible(self, PlayerTrail.trail[PREV(marker)])) {
|
||||
return PlayerTrail.trail[PREV(marker)];
|
||||
}
|
||||
|
||||
return PlayerTrail.trail[marker];
|
||||
}
|
||||
|
||||
static edict_t PickNext(edict_t self) {
|
||||
int marker;
|
||||
int n;
|
||||
|
||||
if (!trail_active)
|
||||
return null;
|
||||
|
||||
for (marker = trail_head, n = PlayerTrail.TRAIL_LENGTH; n > 0; n--) {
|
||||
if (PlayerTrail.trail[marker].timestamp <= self.monsterinfo.trail_time)
|
||||
marker = NEXT(marker);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return PlayerTrail.trail[marker];
|
||||
}
|
||||
|
||||
static edict_t LastSpot() {
|
||||
return PlayerTrail.trail[PREV(trail_head)];
|
||||
}
|
||||
}
|
||||
1056
src/main/java/lwjake2/game/PlayerView.java
Normal file
1056
src/main/java/lwjake2/game/PlayerView.java
Normal file
File diff suppressed because it is too large
Load Diff
1505
src/main/java/lwjake2/game/PlayerWeapon.java
Normal file
1505
src/main/java/lwjake2/game/PlayerWeapon.java
Normal file
File diff suppressed because it is too large
Load Diff
54
src/main/java/lwjake2/game/SuperAdapter.java
Normal file
54
src/main/java/lwjake2/game/SuperAdapter.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.qcommon.Com;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
public abstract class SuperAdapter {
|
||||
|
||||
/** Constructor, does the adapter registration. */
|
||||
public SuperAdapter() {
|
||||
register(this, getID());
|
||||
}
|
||||
|
||||
/** Adapter registration. */
|
||||
private static void register(SuperAdapter sa, String id) {
|
||||
adapters.put(id, sa);
|
||||
}
|
||||
|
||||
/** Adapter repository. */
|
||||
private static Hashtable<String, SuperAdapter> adapters= new Hashtable<String, SuperAdapter>();
|
||||
|
||||
/** Returns the adapter from the repository given by its ID. */
|
||||
public static SuperAdapter getFromID(String key) {
|
||||
SuperAdapter sa= (SuperAdapter) adapters.get(key);
|
||||
|
||||
// try to create the adapter
|
||||
if (sa == null) {
|
||||
Com.DPrintf("SuperAdapter.getFromID():adapter not found->" + key + "\n");
|
||||
}
|
||||
|
||||
return sa;
|
||||
}
|
||||
|
||||
/** Returns the Adapter-ID. */
|
||||
public abstract String getID();
|
||||
}
|
||||
156
src/main/java/lwjake2/game/client_persistant_t.java
Normal file
156
src/main/java/lwjake2/game/client_persistant_t.java
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.util.QuakeFile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class client_persistant_t {
|
||||
|
||||
public void set(client_persistant_t from) {
|
||||
|
||||
userinfo= from.userinfo;
|
||||
netname= from.netname;
|
||||
hand= from.hand;
|
||||
connected= from.connected;
|
||||
health= from.health;
|
||||
max_health= from.max_health;
|
||||
savedFlags= from.savedFlags;
|
||||
selected_item= from.selected_item;
|
||||
System.arraycopy(from.inventory, 0, inventory, 0, inventory.length);
|
||||
max_bullets= from.max_bullets;
|
||||
max_shells= from.max_shells;
|
||||
max_rockets= from.max_rockets;
|
||||
max_grenades= from.max_grenades;
|
||||
max_cells= from.max_cells;
|
||||
max_slugs= from.max_slugs;
|
||||
weapon= from.weapon;
|
||||
lastweapon= from.lastweapon;
|
||||
power_cubes= from.power_cubes;
|
||||
score= from.score;
|
||||
game_helpchanged= from.game_helpchanged;
|
||||
helpchanged= from.helpchanged;
|
||||
spectator= from.spectator;
|
||||
}
|
||||
|
||||
// client data that stays across multiple level loads
|
||||
String userinfo= "";
|
||||
String netname= "";
|
||||
int hand;
|
||||
|
||||
boolean connected; // a loadgame will leave valid entities that
|
||||
// just don't have a connection yet
|
||||
|
||||
// values saved and restored from edicts when changing levels
|
||||
int health;
|
||||
int max_health;
|
||||
int savedFlags;
|
||||
|
||||
int selected_item;
|
||||
int inventory[]= new int[Defines.MAX_ITEMS];
|
||||
|
||||
// ammo capacities
|
||||
public int max_bullets;
|
||||
public int max_shells;
|
||||
public int max_rockets;
|
||||
public int max_grenades;
|
||||
public int max_cells;
|
||||
public int max_slugs;
|
||||
//pointer
|
||||
gitem_t weapon;
|
||||
//pointer
|
||||
gitem_t lastweapon;
|
||||
int power_cubes; // used for tracking the cubes in coop games
|
||||
int score; // for calculating total unit score in coop games
|
||||
int game_helpchanged;
|
||||
int helpchanged;
|
||||
boolean spectator; // client is a spectator
|
||||
|
||||
/** Reads a client_persistant structure from a file. */
|
||||
public void read(QuakeFile f) throws IOException {
|
||||
|
||||
userinfo= f.readString();
|
||||
netname= f.readString();
|
||||
|
||||
hand= f.readInt();
|
||||
|
||||
connected= f.readInt() != 0;
|
||||
health= f.readInt();
|
||||
|
||||
max_health= f.readInt();
|
||||
savedFlags= f.readInt();
|
||||
selected_item= f.readInt();
|
||||
|
||||
for (int n= 0; n < Defines.MAX_ITEMS; n++)
|
||||
inventory[n]= f.readInt();
|
||||
|
||||
max_bullets= f.readInt();
|
||||
max_shells= f.readInt();
|
||||
max_rockets= f.readInt();
|
||||
max_grenades= f.readInt();
|
||||
max_cells= f.readInt();
|
||||
max_slugs= f.readInt();
|
||||
|
||||
weapon= f.readItem();
|
||||
lastweapon= f.readItem();
|
||||
power_cubes= f.readInt();
|
||||
score= f.readInt();
|
||||
|
||||
game_helpchanged= f.readInt();
|
||||
helpchanged= f.readInt();
|
||||
spectator= f.readInt() != 0;
|
||||
}
|
||||
|
||||
/** Writes a client_persistant structure to a file. */
|
||||
public void write(QuakeFile f) throws IOException {
|
||||
// client persistant_t
|
||||
f.writeString(userinfo);
|
||||
f.writeString(netname);
|
||||
|
||||
f.writeInt(hand);
|
||||
|
||||
f.writeInt(connected ? 1 : 0);
|
||||
f.writeInt(health);
|
||||
|
||||
f.writeInt(max_health);
|
||||
f.writeInt(savedFlags);
|
||||
f.writeInt(selected_item);
|
||||
|
||||
for (int n= 0; n < Defines.MAX_ITEMS; n++)
|
||||
f.writeInt(inventory[n]);
|
||||
|
||||
f.writeInt(max_bullets);
|
||||
f.writeInt(max_shells);
|
||||
f.writeInt(max_rockets);
|
||||
f.writeInt(max_grenades);
|
||||
f.writeInt(max_cells);
|
||||
f.writeInt(max_slugs);
|
||||
|
||||
f.writeItem(weapon);
|
||||
f.writeItem(lastweapon);
|
||||
f.writeInt(power_cubes);
|
||||
f.writeInt(score);
|
||||
|
||||
f.writeInt(game_helpchanged);
|
||||
f.writeInt(helpchanged);
|
||||
f.writeInt(spectator ? 1 : 0);
|
||||
}
|
||||
}
|
||||
88
src/main/java/lwjake2/game/client_respawn_t.java
Normal file
88
src/main/java/lwjake2/game/client_respawn_t.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.util.Math3D;
|
||||
import lwjake2.util.QuakeFile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/** Client data that stays across deathmatch respawns. */
|
||||
public class client_respawn_t
|
||||
{
|
||||
/** What to set client->pers to on a respawn */
|
||||
protected client_persistant_t coop_respawn = new client_persistant_t();
|
||||
|
||||
/** Level.framenum the client entered the game. */
|
||||
protected int enterframe;
|
||||
|
||||
/** frags, etc. */
|
||||
protected int score;
|
||||
|
||||
/** angles sent over in the last command. */
|
||||
protected float cmd_angles[] = { 0, 0, 0 };
|
||||
|
||||
/** client is a spectator. */
|
||||
protected boolean spectator;
|
||||
|
||||
|
||||
/** Copies the client respawn data. */
|
||||
public void set(client_respawn_t from)
|
||||
{
|
||||
coop_respawn.set(from.coop_respawn);
|
||||
enterframe = from.enterframe;
|
||||
score = from.score;
|
||||
Math3D.VectorCopy(from.cmd_angles, cmd_angles);
|
||||
spectator = from.spectator;
|
||||
}
|
||||
|
||||
/** Clears the client reaspawn informations. */
|
||||
public void clear()
|
||||
{
|
||||
coop_respawn = new client_persistant_t();
|
||||
enterframe = 0;
|
||||
score = 0;
|
||||
Math3D.VectorClear(cmd_angles);
|
||||
spectator = false;
|
||||
}
|
||||
|
||||
/** Reads a client_respawn from a file. */
|
||||
public void read(QuakeFile f) throws IOException
|
||||
{
|
||||
coop_respawn.read(f);
|
||||
enterframe = f.readInt();
|
||||
score = f.readInt();
|
||||
cmd_angles[0] = f.readFloat();
|
||||
cmd_angles[1] = f.readFloat();
|
||||
cmd_angles[2] = f.readFloat();
|
||||
spectator = f.readInt() != 0;
|
||||
}
|
||||
|
||||
/** Writes a client_respawn to a file. */
|
||||
public void write(QuakeFile f) throws IOException
|
||||
{
|
||||
coop_respawn.write(f);
|
||||
f.writeInt(enterframe);
|
||||
f.writeInt(score);
|
||||
f.writeFloat(cmd_angles[0]);
|
||||
f.writeFloat(cmd_angles[1]);
|
||||
f.writeFloat(cmd_angles[2]);
|
||||
f.writeInt(spectator?1:0);
|
||||
}
|
||||
}
|
||||
26
src/main/java/lwjake2/game/cmdalias_t.java
Normal file
26
src/main/java/lwjake2/game/cmdalias_t.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public final class cmdalias_t
|
||||
{
|
||||
public cmdalias_t next;
|
||||
public String name = "";
|
||||
public String value;
|
||||
}
|
||||
27
src/main/java/lwjake2/game/cmodel_t.java
Normal file
27
src/main/java/lwjake2/game/cmodel_t.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public class cmodel_t
|
||||
{
|
||||
public float[] mins = { 0, 0, 0 };
|
||||
public float[] maxs = { 0, 0, 0 };
|
||||
public float[] origin = { 0, 0, 0 }; // for sounds or lights
|
||||
public int headnode;
|
||||
}
|
||||
50
src/main/java/lwjake2/game/cplane_t.java
Normal file
50
src/main/java/lwjake2/game/cplane_t.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.util.Math3D;
|
||||
|
||||
public class cplane_t
|
||||
{
|
||||
public float normal[] = new float[3];
|
||||
public float dist;
|
||||
/** This is for fast side tests, 0=xplane, 1=yplane, 2=zplane and 3=arbitrary. */
|
||||
public byte type;
|
||||
/** This represents signx + (signy<<1) + (signz << 1). */
|
||||
public byte signbits; // signx + (signy<<1) + (signz<<1)
|
||||
public byte pad[] = { 0, 0 };
|
||||
|
||||
public void set(cplane_t c) {
|
||||
Math3D.set(normal, c.normal);
|
||||
dist = c.dist;
|
||||
type = c.type;
|
||||
signbits = c.signbits;
|
||||
pad[0] = c.pad[0];
|
||||
pad[1] = c.pad[1];
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
Math3D.VectorClear(normal);
|
||||
dist = 0;
|
||||
type = 0;
|
||||
signbits = 0;
|
||||
pad[0] = 0;
|
||||
pad[1] = 0;
|
||||
}
|
||||
}
|
||||
26
src/main/java/lwjake2/game/csurface_t.java
Normal file
26
src/main/java/lwjake2/game/csurface_t.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public class csurface_t
|
||||
{
|
||||
public String name = "";
|
||||
public int flags;
|
||||
public int value;
|
||||
}
|
||||
33
src/main/java/lwjake2/game/cvar_t.java
Normal file
33
src/main/java/lwjake2/game/cvar_t.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
/**
|
||||
* cvar_t implements the struct cvar_t of the C version
|
||||
*/
|
||||
public final class cvar_t
|
||||
{
|
||||
public String name;
|
||||
public String string;
|
||||
public String latched_string;
|
||||
public int flags = 0;
|
||||
public boolean modified = false;
|
||||
public float value = 0.0f;
|
||||
public cvar_t next = null;
|
||||
}
|
||||
774
src/main/java/lwjake2/game/edict_t.java
Normal file
774
src/main/java/lwjake2/game/edict_t.java
Normal file
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.util.Lib;
|
||||
import lwjake2.util.QuakeFile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Slf4j
|
||||
public class edict_t {
|
||||
/** Constructor. */
|
||||
public edict_t(int i) {
|
||||
s.number = i;
|
||||
index = i;
|
||||
}
|
||||
|
||||
/** Used during level loading. */
|
||||
public void cleararealinks() {
|
||||
area = new link_t(this);
|
||||
}
|
||||
|
||||
/** Integrated entity state. */
|
||||
public entity_state_t s = new entity_state_t(this);
|
||||
|
||||
public boolean inuse;
|
||||
|
||||
public int linkcount;
|
||||
|
||||
/**
|
||||
* FIXME: move these fields to a server private sv_entity_t. linked to a
|
||||
* division node or leaf.
|
||||
*/
|
||||
public link_t area = new link_t(this);
|
||||
|
||||
/** if -1, use headnode instead. */
|
||||
public int num_clusters;
|
||||
|
||||
public int clusternums[] = new int[Defines.MAX_ENT_CLUSTERS];
|
||||
|
||||
/** unused if num_clusters != -1. */
|
||||
public int headnode;
|
||||
|
||||
public int areanum, areanum2;
|
||||
|
||||
//================================
|
||||
|
||||
/** SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc. */
|
||||
public int svflags;
|
||||
|
||||
public float[] mins = { 0, 0, 0 };
|
||||
|
||||
public float[] maxs = { 0, 0, 0 };
|
||||
|
||||
public float[] absmin = { 0, 0, 0 };
|
||||
|
||||
public float[] absmax = { 0, 0, 0 };
|
||||
|
||||
public float[] size = { 0, 0, 0 };
|
||||
|
||||
public int solid;
|
||||
|
||||
public int clipmask;
|
||||
|
||||
//================================
|
||||
public int movetype;
|
||||
|
||||
public int flags;
|
||||
|
||||
public String model = null;
|
||||
|
||||
/** sv.time when the object was freed. */
|
||||
public float freetime;
|
||||
|
||||
//
|
||||
// only used locally in game, not by server
|
||||
//
|
||||
public String message = null;
|
||||
|
||||
public String classname = "";
|
||||
|
||||
public int spawnflags;
|
||||
|
||||
public float timestamp;
|
||||
|
||||
/** set in qe3, -1 = up, -2 = down */
|
||||
public float angle;
|
||||
|
||||
public String target = null;
|
||||
|
||||
public String targetname = null;
|
||||
|
||||
public String killtarget = null;
|
||||
|
||||
public String team = null;
|
||||
|
||||
public String pathtarget = null;
|
||||
|
||||
public String deathtarget = null;
|
||||
|
||||
public String combattarget = null;
|
||||
|
||||
public edict_t target_ent = null;
|
||||
|
||||
public float speed, accel, decel;
|
||||
|
||||
public float[] movedir = { 0, 0, 0 };
|
||||
|
||||
public float[] pos1 = { 0, 0, 0 };
|
||||
|
||||
public float[] pos2 = { 0, 0, 0 };
|
||||
|
||||
public float[] velocity = { 0, 0, 0 };
|
||||
|
||||
public float[] avelocity = { 0, 0, 0 };
|
||||
|
||||
public int mass;
|
||||
|
||||
public float air_finished;
|
||||
|
||||
/** per entity gravity multiplier (1.0 is normal). */
|
||||
public float gravity;
|
||||
|
||||
/** use for lowgrav artifact, flares. */
|
||||
|
||||
public edict_t goalentity = null;
|
||||
|
||||
public edict_t movetarget = null;
|
||||
|
||||
public float yaw_speed;
|
||||
|
||||
public float ideal_yaw;
|
||||
|
||||
public float nextthink;
|
||||
|
||||
public EntThinkAdapter prethink = null;
|
||||
|
||||
public EntThinkAdapter think = null;
|
||||
|
||||
public EntBlockedAdapter blocked = null;
|
||||
|
||||
public EntTouchAdapter touch = null;
|
||||
|
||||
public EntUseAdapter use = null;
|
||||
|
||||
public EntPainAdapter pain = null;
|
||||
|
||||
public EntDieAdapter die = null;
|
||||
|
||||
/** Are all these legit? do we need more/less of them? */
|
||||
public float touch_debounce_time;
|
||||
|
||||
public float pain_debounce_time;
|
||||
|
||||
public float damage_debounce_time;
|
||||
|
||||
/** Move to clientinfo. */
|
||||
public float fly_sound_debounce_time;
|
||||
|
||||
public float last_move_time;
|
||||
|
||||
public int health;
|
||||
|
||||
public int max_health;
|
||||
|
||||
public int gib_health;
|
||||
|
||||
public int deadflag;
|
||||
|
||||
public int show_hostile;
|
||||
|
||||
public float powerarmor_time;
|
||||
|
||||
/** target_changelevel. */
|
||||
public String map = null;
|
||||
|
||||
/** Height above origin where eyesight is determined. */
|
||||
public int viewheight;
|
||||
|
||||
public int takedamage;
|
||||
|
||||
public int dmg;
|
||||
|
||||
public int radius_dmg;
|
||||
|
||||
public float dmg_radius;
|
||||
|
||||
/** make this a spawntemp var? */
|
||||
public int sounds;
|
||||
|
||||
public int count;
|
||||
|
||||
public edict_t chain = null;
|
||||
|
||||
public edict_t enemy = null;
|
||||
|
||||
public edict_t oldenemy = null;
|
||||
|
||||
public edict_t activator = null;
|
||||
|
||||
public edict_t groundentity = null;
|
||||
|
||||
public int groundentity_linkcount;
|
||||
|
||||
public edict_t teamchain = null;
|
||||
|
||||
public edict_t teammaster = null;
|
||||
|
||||
/** can go in client only. */
|
||||
public edict_t mynoise = null;
|
||||
|
||||
public edict_t mynoise2 = null;
|
||||
|
||||
public int noise_index;
|
||||
|
||||
public int noise_index2;
|
||||
|
||||
public float volume;
|
||||
|
||||
public float attenuation;
|
||||
|
||||
/** Timing variables. */
|
||||
public float wait;
|
||||
|
||||
/** before firing targets... */
|
||||
public float delay;
|
||||
|
||||
public float random;
|
||||
|
||||
public float teleport_time;
|
||||
|
||||
public int watertype;
|
||||
|
||||
public int waterlevel;
|
||||
|
||||
public float[] move_origin = { 0, 0, 0 };
|
||||
|
||||
public float[] move_angles = { 0, 0, 0 };
|
||||
|
||||
/** move this to clientinfo? . */
|
||||
public int light_level;
|
||||
|
||||
/** also used as areaportal number. */
|
||||
public int style;
|
||||
|
||||
public gitem_t item; // for bonus items
|
||||
|
||||
/** common integrated data blocks. */
|
||||
public moveinfo_t moveinfo = new moveinfo_t();
|
||||
|
||||
public monsterinfo_t monsterinfo = new monsterinfo_t();
|
||||
|
||||
public gclient_t client;
|
||||
|
||||
public edict_t owner;
|
||||
|
||||
/** Introduced by rst. */
|
||||
public int index;
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
public boolean setField(String key, String value) {
|
||||
|
||||
if (key.equals("classname")) {
|
||||
classname = GameSpawn.ED_NewString(value);
|
||||
return true;
|
||||
} // F_LSTRING),
|
||||
|
||||
if (key.equals("model")) {
|
||||
model = GameSpawn.ED_NewString(value);
|
||||
return true;
|
||||
} // F_LSTRING),
|
||||
|
||||
if (key.equals("spawnflags")) {
|
||||
spawnflags = Lib.atoi(value);
|
||||
return true;
|
||||
} // F_INT),
|
||||
|
||||
if (key.equals("speed")) {
|
||||
speed = Lib.atof(value);
|
||||
return true;
|
||||
} // F_FLOAT),
|
||||
|
||||
if (key.equals("accel")) {
|
||||
accel = Lib.atof(value);
|
||||
return true;
|
||||
} // F_FLOAT),
|
||||
|
||||
if (key.equals("decel")) {
|
||||
decel = Lib.atof(value);
|
||||
return true;
|
||||
} // F_FLOAT),
|
||||
|
||||
if (key.equals("target")) {
|
||||
target = GameSpawn.ED_NewString(value);
|
||||
return true;
|
||||
} // F_LSTRING),
|
||||
|
||||
if (key.equals("targetname")) {
|
||||
targetname = GameSpawn.ED_NewString(value);
|
||||
return true;
|
||||
} // F_LSTRING),
|
||||
|
||||
if (key.equals("pathtarget")) {
|
||||
pathtarget = GameSpawn.ED_NewString(value);
|
||||
return true;
|
||||
} // F_LSTRING),
|
||||
|
||||
if (key.equals("deathtarget")) {
|
||||
deathtarget = GameSpawn.ED_NewString(value);
|
||||
return true;
|
||||
} // F_LSTRING),
|
||||
if (key.equals("killtarget")) {
|
||||
killtarget = GameSpawn.ED_NewString(value);
|
||||
return true;
|
||||
} // F_LSTRING),
|
||||
|
||||
if (key.equals("combattarget")) {
|
||||
combattarget = GameSpawn.ED_NewString(value);
|
||||
return true;
|
||||
} // F_LSTRING),
|
||||
|
||||
if (key.equals("message")) {
|
||||
message = GameSpawn.ED_NewString(value);
|
||||
return true;
|
||||
} // F_LSTRING),
|
||||
|
||||
if (key.equals("team")) {
|
||||
team = GameSpawn.ED_NewString(value);
|
||||
Com.dprintln("Monster Team:" + team);
|
||||
return true;
|
||||
} // F_LSTRING),
|
||||
|
||||
if (key.equals("wait")) {
|
||||
wait = Lib.atof(value);
|
||||
return true;
|
||||
} // F_FLOAT),
|
||||
|
||||
if (key.equals("delay")) {
|
||||
delay = Lib.atof(value);
|
||||
return true;
|
||||
} // F_FLOAT),
|
||||
|
||||
if (key.equals("random")) {
|
||||
random = Lib.atof(value);
|
||||
return true;
|
||||
} // F_FLOAT),
|
||||
|
||||
if (key.equals("move_origin")) {
|
||||
move_origin = Lib.atov(value);
|
||||
return true;
|
||||
} // F_VECTOR),
|
||||
|
||||
if (key.equals("move_angles")) {
|
||||
move_angles = Lib.atov(value);
|
||||
return true;
|
||||
} // F_VECTOR),
|
||||
|
||||
if (key.equals("style")) {
|
||||
style = Lib.atoi(value);
|
||||
return true;
|
||||
} // F_INT),
|
||||
|
||||
if (key.equals("count")) {
|
||||
count = Lib.atoi(value);
|
||||
return true;
|
||||
} // F_INT),
|
||||
|
||||
if (key.equals("health")) {
|
||||
health = Lib.atoi(value);
|
||||
return true;
|
||||
} // F_INT),
|
||||
|
||||
if (key.equals("sounds")) {
|
||||
sounds = Lib.atoi(value);
|
||||
return true;
|
||||
} // F_INT),
|
||||
|
||||
if (key.equals("light")) {
|
||||
return true;
|
||||
} // F_IGNORE),
|
||||
|
||||
if (key.equals("dmg")) {
|
||||
dmg = Lib.atoi(value);
|
||||
return true;
|
||||
} // F_INT),
|
||||
|
||||
if (key.equals("mass")) {
|
||||
mass = Lib.atoi(value);
|
||||
return true;
|
||||
} // F_INT),
|
||||
|
||||
if (key.equals("volume")) {
|
||||
volume = Lib.atof(value);
|
||||
return true;
|
||||
} // F_FLOAT),
|
||||
|
||||
if (key.equals("attenuation")) {
|
||||
attenuation = Lib.atof(value);
|
||||
return true;
|
||||
} // F_FLOAT),
|
||||
|
||||
if (key.equals("map")) {
|
||||
map = GameSpawn.ED_NewString(value);
|
||||
return true;
|
||||
} // F_LSTRING),
|
||||
|
||||
if (key.equals("origin")) {
|
||||
s.origin = Lib.atov(value);
|
||||
return true;
|
||||
} // F_VECTOR),
|
||||
|
||||
if (key.equals("angles")) {
|
||||
s.angles = Lib.atov(value);
|
||||
return true;
|
||||
} // F_VECTOR),
|
||||
|
||||
if (key.equals("angle")) {
|
||||
s.angles = new float[] { 0, Lib.atof(value), 0 };
|
||||
return true;
|
||||
} // F_ANGLEHACK),
|
||||
|
||||
if (key.equals("item")) {
|
||||
GameBase.gi.error("ent.set(\"item\") called.");
|
||||
return true;
|
||||
} // F_ITEM)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Writes the entity to the file. */
|
||||
public void write(QuakeFile f) throws IOException {
|
||||
|
||||
s.write(f);
|
||||
f.writeBoolean(inuse);
|
||||
f.writeInt(linkcount);
|
||||
f.writeInt(num_clusters);
|
||||
|
||||
f.writeInt(9999);
|
||||
|
||||
if (clusternums == null)
|
||||
f.writeInt(-1);
|
||||
else {
|
||||
f.writeInt(Defines.MAX_ENT_CLUSTERS);
|
||||
for (int n = 0; n < Defines.MAX_ENT_CLUSTERS; n++)
|
||||
f.writeInt(clusternums[n]);
|
||||
|
||||
}
|
||||
f.writeInt(headnode);
|
||||
f.writeInt(areanum);
|
||||
f.writeInt(areanum2);
|
||||
f.writeInt(svflags);
|
||||
f.writeVector(mins);
|
||||
f.writeVector(maxs);
|
||||
f.writeVector(absmin);
|
||||
f.writeVector(absmax);
|
||||
f.writeVector(size);
|
||||
f.writeInt(solid);
|
||||
f.writeInt(clipmask);
|
||||
|
||||
f.writeInt(movetype);
|
||||
f.writeInt(flags);
|
||||
|
||||
f.writeString(model);
|
||||
f.writeFloat(freetime);
|
||||
f.writeString(message);
|
||||
f.writeString(classname);
|
||||
f.writeInt(spawnflags);
|
||||
f.writeFloat(timestamp);
|
||||
|
||||
f.writeFloat(angle);
|
||||
|
||||
f.writeString(target);
|
||||
f.writeString(targetname);
|
||||
f.writeString(killtarget);
|
||||
f.writeString(team);
|
||||
f.writeString(pathtarget);
|
||||
f.writeString(deathtarget);
|
||||
f.writeString(combattarget);
|
||||
|
||||
f.writeEdictRef(target_ent);
|
||||
|
||||
f.writeFloat(speed);
|
||||
f.writeFloat(accel);
|
||||
f.writeFloat(decel);
|
||||
|
||||
f.writeVector(movedir);
|
||||
|
||||
f.writeVector(pos1);
|
||||
f.writeVector(pos2);
|
||||
|
||||
f.writeVector(velocity);
|
||||
f.writeVector(avelocity);
|
||||
|
||||
f.writeInt(mass);
|
||||
f.writeFloat(air_finished);
|
||||
|
||||
f.writeFloat(gravity);
|
||||
|
||||
f.writeEdictRef(goalentity);
|
||||
f.writeEdictRef(movetarget);
|
||||
|
||||
f.writeFloat(yaw_speed);
|
||||
f.writeFloat(ideal_yaw);
|
||||
|
||||
f.writeFloat(nextthink);
|
||||
|
||||
f.writeAdapter(prethink);
|
||||
f.writeAdapter(think);
|
||||
f.writeAdapter(blocked);
|
||||
|
||||
f.writeAdapter(touch);
|
||||
f.writeAdapter(use);
|
||||
f.writeAdapter(pain);
|
||||
f.writeAdapter(die);
|
||||
|
||||
f.writeFloat(touch_debounce_time);
|
||||
f.writeFloat(pain_debounce_time);
|
||||
f.writeFloat(damage_debounce_time);
|
||||
|
||||
f.writeFloat(fly_sound_debounce_time);
|
||||
f.writeFloat(last_move_time);
|
||||
|
||||
f.writeInt(health);
|
||||
f.writeInt(max_health);
|
||||
|
||||
f.writeInt(gib_health);
|
||||
f.writeInt(deadflag);
|
||||
f.writeInt(show_hostile);
|
||||
|
||||
f.writeFloat(powerarmor_time);
|
||||
|
||||
f.writeString(map);
|
||||
|
||||
f.writeInt(viewheight);
|
||||
f.writeInt(takedamage);
|
||||
f.writeInt(dmg);
|
||||
f.writeInt(radius_dmg);
|
||||
f.writeFloat(dmg_radius);
|
||||
|
||||
f.writeInt(sounds);
|
||||
f.writeInt(count);
|
||||
|
||||
f.writeEdictRef(chain);
|
||||
f.writeEdictRef(enemy);
|
||||
f.writeEdictRef(oldenemy);
|
||||
f.writeEdictRef(activator);
|
||||
f.writeEdictRef(groundentity);
|
||||
f.writeInt(groundentity_linkcount);
|
||||
f.writeEdictRef(teamchain);
|
||||
f.writeEdictRef(teammaster);
|
||||
|
||||
f.writeEdictRef(mynoise);
|
||||
f.writeEdictRef(mynoise2);
|
||||
|
||||
f.writeInt(noise_index);
|
||||
f.writeInt(noise_index2);
|
||||
|
||||
f.writeFloat(volume);
|
||||
f.writeFloat(attenuation);
|
||||
f.writeFloat(wait);
|
||||
f.writeFloat(delay);
|
||||
f.writeFloat(random);
|
||||
|
||||
f.writeFloat(teleport_time);
|
||||
|
||||
f.writeInt(watertype);
|
||||
f.writeInt(waterlevel);
|
||||
f.writeVector(move_origin);
|
||||
f.writeVector(move_angles);
|
||||
|
||||
f.writeInt(light_level);
|
||||
f.writeInt(style);
|
||||
|
||||
f.writeItem(item);
|
||||
|
||||
moveinfo.write(f);
|
||||
monsterinfo.write(f);
|
||||
if (client == null)
|
||||
f.writeInt(-1);
|
||||
else
|
||||
f.writeInt(client.index);
|
||||
|
||||
f.writeEdictRef(owner);
|
||||
|
||||
// rst's checker :-)
|
||||
f.writeInt(9876);
|
||||
}
|
||||
|
||||
/** Reads the entity from the file. */
|
||||
public void read(QuakeFile f) throws IOException {
|
||||
s.read(f);
|
||||
inuse = f.readBoolean();
|
||||
linkcount = f.readInt();
|
||||
num_clusters = f.readInt();
|
||||
|
||||
if (f.readInt() != 9999)
|
||||
new Throwable("wrong read pos!").printStackTrace();
|
||||
|
||||
int len = f.readInt();
|
||||
|
||||
if (len == -1)
|
||||
clusternums = null;
|
||||
else {
|
||||
clusternums = new int[Defines.MAX_ENT_CLUSTERS];
|
||||
for (int n = 0; n < Defines.MAX_ENT_CLUSTERS; n++)
|
||||
clusternums[n] = f.readInt();
|
||||
}
|
||||
|
||||
headnode = f.readInt();
|
||||
areanum = f.readInt();
|
||||
areanum2 = f.readInt();
|
||||
svflags = f.readInt();
|
||||
mins = f.readVector();
|
||||
maxs = f.readVector();
|
||||
absmin = f.readVector();
|
||||
absmax = f.readVector();
|
||||
size = f.readVector();
|
||||
solid = f.readInt();
|
||||
clipmask = f.readInt();
|
||||
|
||||
movetype = f.readInt();
|
||||
flags = f.readInt();
|
||||
|
||||
model = f.readString();
|
||||
freetime = f.readFloat();
|
||||
message = f.readString();
|
||||
classname = f.readString();
|
||||
spawnflags = f.readInt();
|
||||
timestamp = f.readFloat();
|
||||
|
||||
angle = f.readFloat();
|
||||
|
||||
target = f.readString();
|
||||
targetname = f.readString();
|
||||
killtarget = f.readString();
|
||||
team = f.readString();
|
||||
pathtarget = f.readString();
|
||||
deathtarget = f.readString();
|
||||
combattarget = f.readString();
|
||||
|
||||
target_ent = f.readEdictRef();
|
||||
|
||||
speed = f.readFloat();
|
||||
accel = f.readFloat();
|
||||
decel = f.readFloat();
|
||||
|
||||
movedir = f.readVector();
|
||||
|
||||
pos1 = f.readVector();
|
||||
pos2 = f.readVector();
|
||||
|
||||
velocity = f.readVector();
|
||||
avelocity = f.readVector();
|
||||
|
||||
mass = f.readInt();
|
||||
air_finished = f.readFloat();
|
||||
|
||||
gravity = f.readFloat();
|
||||
|
||||
goalentity = f.readEdictRef();
|
||||
movetarget = f.readEdictRef();
|
||||
|
||||
yaw_speed = f.readFloat();
|
||||
ideal_yaw = f.readFloat();
|
||||
|
||||
nextthink = f.readFloat();
|
||||
|
||||
prethink = (EntThinkAdapter) f.readAdapter();
|
||||
think = (EntThinkAdapter) f.readAdapter();
|
||||
blocked = (EntBlockedAdapter) f.readAdapter();
|
||||
|
||||
touch = (EntTouchAdapter) f.readAdapter();
|
||||
use = (EntUseAdapter) f.readAdapter();
|
||||
pain = (EntPainAdapter) f.readAdapter();
|
||||
die = (EntDieAdapter) f.readAdapter();
|
||||
|
||||
touch_debounce_time = f.readFloat();
|
||||
pain_debounce_time = f.readFloat();
|
||||
damage_debounce_time = f.readFloat();
|
||||
|
||||
fly_sound_debounce_time = f.readFloat();
|
||||
last_move_time = f.readFloat();
|
||||
|
||||
health = f.readInt();
|
||||
max_health = f.readInt();
|
||||
|
||||
gib_health = f.readInt();
|
||||
deadflag = f.readInt();
|
||||
show_hostile = f.readInt();
|
||||
|
||||
powerarmor_time = f.readFloat();
|
||||
|
||||
map = f.readString();
|
||||
|
||||
viewheight = f.readInt();
|
||||
takedamage = f.readInt();
|
||||
dmg = f.readInt();
|
||||
radius_dmg = f.readInt();
|
||||
dmg_radius = f.readFloat();
|
||||
|
||||
sounds = f.readInt();
|
||||
count = f.readInt();
|
||||
|
||||
chain = f.readEdictRef();
|
||||
enemy = f.readEdictRef();
|
||||
|
||||
oldenemy = f.readEdictRef();
|
||||
activator = f.readEdictRef();
|
||||
groundentity = f.readEdictRef();
|
||||
|
||||
groundentity_linkcount = f.readInt();
|
||||
teamchain = f.readEdictRef();
|
||||
teammaster = f.readEdictRef();
|
||||
|
||||
mynoise = f.readEdictRef();
|
||||
mynoise2 = f.readEdictRef();
|
||||
|
||||
noise_index = f.readInt();
|
||||
noise_index2 = f.readInt();
|
||||
|
||||
volume = f.readFloat();
|
||||
attenuation = f.readFloat();
|
||||
wait = f.readFloat();
|
||||
delay = f.readFloat();
|
||||
random = f.readFloat();
|
||||
|
||||
teleport_time = f.readFloat();
|
||||
|
||||
watertype = f.readInt();
|
||||
waterlevel = f.readInt();
|
||||
move_origin = f.readVector();
|
||||
move_angles = f.readVector();
|
||||
|
||||
light_level = f.readInt();
|
||||
style = f.readInt();
|
||||
|
||||
item = f.readItem();
|
||||
|
||||
moveinfo.read(f);
|
||||
monsterinfo.read(f);
|
||||
|
||||
int ndx = f.readInt();
|
||||
if (ndx == -1)
|
||||
client = null;
|
||||
else
|
||||
client = GameBase.game.clients[ndx];
|
||||
|
||||
owner = f.readEdictRef();
|
||||
|
||||
// rst's checker :-)
|
||||
if (f.readInt() != 9876)
|
||||
log.error("ent load check failed for num {}", index);
|
||||
}
|
||||
}
|
||||
164
src/main/java/lwjake2/game/entity_state_t.java
Normal file
164
src/main/java/lwjake2/game/entity_state_t.java
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import lwjake2.util.Math3D;
|
||||
import lwjake2.util.QuakeFile;
|
||||
|
||||
public class entity_state_t implements Cloneable
|
||||
{
|
||||
/** entity_state_t is the information conveyed from the server
|
||||
in an update message about entities that the client will
|
||||
need to render in some way. */
|
||||
public entity_state_t(edict_t ent)
|
||||
{
|
||||
this.surrounding_ent = ent;
|
||||
if (ent != null)
|
||||
number = ent.index;
|
||||
}
|
||||
|
||||
/** edict index. TODO: this is critical. The index has to be proper managed. */
|
||||
public int number = 0;
|
||||
// TODO: why was this introduced?
|
||||
public edict_t surrounding_ent = null;
|
||||
public float[] origin = { 0, 0, 0 };
|
||||
public float[] angles = { 0, 0, 0 };
|
||||
|
||||
/** for lerping. */
|
||||
public float[] old_origin = { 0, 0, 0 };
|
||||
public int modelindex;
|
||||
/** weapons, CTF flags, etc. */
|
||||
public int modelindex2, modelindex3, modelindex4;
|
||||
public int frame;
|
||||
public int skinnum;
|
||||
/** PGM - we're filling it, so it needs to be unsigned. */
|
||||
public int effects;
|
||||
public int renderfx;
|
||||
public int solid;
|
||||
// for client side prediction, 8*(bits 0-4) is x/y radius
|
||||
// 8*(bits 5-9) is z down distance, 8(bits10-15) is z up
|
||||
// gi.linkentity sets this properly
|
||||
public int sound; // for looping sounds, to guarantee shutoff
|
||||
public int event; // impulse events -- muzzle flashes, footsteps, etc
|
||||
// events only go out for a single frame, they
|
||||
// are automatically cleared each frame
|
||||
|
||||
/** Writes the entity state to the file. */
|
||||
public void write(QuakeFile f) throws IOException
|
||||
{
|
||||
f.writeEdictRef(surrounding_ent);
|
||||
f.writeVector(origin);
|
||||
f.writeVector(angles);
|
||||
f.writeVector(old_origin);
|
||||
|
||||
f.writeInt(modelindex);
|
||||
|
||||
f.writeInt(modelindex2);
|
||||
f.writeInt(modelindex3);
|
||||
f.writeInt(modelindex4);
|
||||
|
||||
f.writeInt(frame);
|
||||
f.writeInt(skinnum);
|
||||
|
||||
f.writeInt(effects);
|
||||
f.writeInt(renderfx);
|
||||
f.writeInt(solid);
|
||||
|
||||
f.writeInt(sound);
|
||||
f.writeInt(event);
|
||||
|
||||
}
|
||||
|
||||
/** Reads the entity state from the file. */
|
||||
public void read(QuakeFile f) throws IOException
|
||||
{
|
||||
surrounding_ent = f.readEdictRef();
|
||||
origin = f.readVector();
|
||||
angles = f.readVector();
|
||||
old_origin = f.readVector();
|
||||
|
||||
modelindex = f.readInt();
|
||||
|
||||
modelindex2= f.readInt();
|
||||
modelindex3= f.readInt();
|
||||
modelindex4= f.readInt();
|
||||
|
||||
frame = f.readInt();
|
||||
skinnum = f.readInt();
|
||||
|
||||
effects = f.readInt();
|
||||
renderfx = f.readInt();
|
||||
solid = f.readInt();
|
||||
|
||||
sound = f.readInt();
|
||||
event = f.readInt();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public entity_state_t getClone()
|
||||
{
|
||||
entity_state_t out = new entity_state_t(this.surrounding_ent);
|
||||
out.set(this);
|
||||
return out;
|
||||
}
|
||||
|
||||
public void set(entity_state_t from)
|
||||
{
|
||||
number = from.number;
|
||||
Math3D.VectorCopy(from.origin, origin);
|
||||
Math3D.VectorCopy(from.angles, angles);
|
||||
Math3D.VectorCopy(from.old_origin, old_origin);
|
||||
|
||||
modelindex = from.modelindex;
|
||||
modelindex2 = from.modelindex2;
|
||||
modelindex3 = from.modelindex3;
|
||||
modelindex4 = from.modelindex4;
|
||||
|
||||
frame = from.frame;
|
||||
skinnum = from.skinnum;
|
||||
effects = from.effects;
|
||||
renderfx = from.renderfx;
|
||||
solid = from.solid;
|
||||
sound = from.sound;
|
||||
event = from.event;
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
//TODO: this is critical. The index has to be proper managed.
|
||||
number = 0;
|
||||
surrounding_ent = null;
|
||||
Math3D.VectorClear(origin);
|
||||
Math3D.VectorClear(angles);
|
||||
Math3D.VectorClear(old_origin);
|
||||
modelindex = 0;
|
||||
modelindex2 = modelindex3 = modelindex4 = 0;
|
||||
frame = 0;
|
||||
skinnum = 0;
|
||||
effects = 0;
|
||||
renderfx = 0;
|
||||
solid = 0;
|
||||
sound = 0;
|
||||
event = 0;
|
||||
}
|
||||
}
|
||||
212
src/main/java/lwjake2/game/game_import_t.java
Normal file
212
src/main/java/lwjake2/game/game_import_t.java
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.qcommon.CM;
|
||||
import lwjake2.qcommon.Cbuf;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.qcommon.Cvar;
|
||||
import lwjake2.qcommon.PMove;
|
||||
import lwjake2.server.SV_GAME;
|
||||
import lwjake2.server.SV_INIT;
|
||||
import lwjake2.server.SV_SEND;
|
||||
import lwjake2.server.SV_WORLD;
|
||||
|
||||
//
|
||||
// collection of functions provided by the main engine
|
||||
//
|
||||
public class game_import_t {
|
||||
// special messages
|
||||
public void bprintf(int printlevel, String s) {
|
||||
SV_SEND.SV_BroadcastPrintf(printlevel, s);
|
||||
}
|
||||
|
||||
public void dprintf(String s) {
|
||||
SV_GAME.PF_dprintf(s);
|
||||
}
|
||||
|
||||
public void cprintf(edict_t ent, int printlevel, String s) {
|
||||
SV_GAME.PF_cprintf(ent, printlevel, s);
|
||||
}
|
||||
|
||||
public void centerprintf(edict_t ent, String s) {
|
||||
SV_GAME.PF_centerprintf(ent, s);
|
||||
}
|
||||
|
||||
public void sound(edict_t ent, int channel, int soundindex, float volume,
|
||||
float attenuation, float timeofs) {
|
||||
SV_GAME.PF_StartSound(ent, channel, soundindex, volume, attenuation,
|
||||
timeofs);
|
||||
}
|
||||
|
||||
public void positioned_sound(float[] origin, edict_t ent, int channel,
|
||||
int soundinedex, float volume, float attenuation, float timeofs) {
|
||||
|
||||
SV_SEND.SV_StartSound(origin, ent, channel, soundinedex, volume,
|
||||
attenuation, timeofs);
|
||||
}
|
||||
|
||||
// config strings hold all the index strings, the lightstyles,
|
||||
// and misc data like the sky definition and cdtrack.
|
||||
// All of the current configstrings are sent to clients when
|
||||
// they connect, and changes are sent to all connected clients.
|
||||
public void configstring(int num, String string) {
|
||||
SV_GAME.PF_Configstring(num, string);
|
||||
}
|
||||
|
||||
public void error(String err) {
|
||||
Com.Error(Defines.ERR_FATAL, err);
|
||||
}
|
||||
|
||||
public void error(int level, String err) {
|
||||
SV_GAME.PF_error(level, err);
|
||||
}
|
||||
|
||||
// the *index functions create configstrings and some internal server state
|
||||
public int modelindex(String name) {
|
||||
return SV_INIT.SV_ModelIndex(name);
|
||||
}
|
||||
|
||||
public int soundindex(String name) {
|
||||
return SV_INIT.SV_SoundIndex(name);
|
||||
}
|
||||
|
||||
public int imageindex(String name) {
|
||||
return SV_INIT.SV_ImageIndex(name);
|
||||
}
|
||||
|
||||
public void setmodel(edict_t ent, String name) {
|
||||
SV_GAME.PF_setmodel(ent, name);
|
||||
}
|
||||
|
||||
// collision detection
|
||||
public trace_t trace(float[] start, float[] mins, float[] maxs,
|
||||
float[] end, edict_t passent, int contentmask) {
|
||||
return SV_WORLD.SV_Trace(start, mins, maxs, end, passent, contentmask);
|
||||
}
|
||||
|
||||
public pmove_t.PointContentsAdapter pointcontents = new pmove_t.PointContentsAdapter() {
|
||||
public int pointcontents(float[] o) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
public boolean inPHS(float[] p1, float[] p2) {
|
||||
return SV_GAME.PF_inPHS(p1, p2);
|
||||
}
|
||||
|
||||
public void SetAreaPortalState(int portalnum, boolean open) {
|
||||
CM.CM_SetAreaPortalState(portalnum, open);
|
||||
}
|
||||
|
||||
public boolean AreasConnected(int area1, int area2) {
|
||||
return CM.CM_AreasConnected(area1, area2);
|
||||
}
|
||||
|
||||
// an entity will never be sent to a client or used for collision
|
||||
// if it is not passed to linkentity. If the size, position, or
|
||||
// solidity changes, it must be relinked.
|
||||
public void linkentity(edict_t ent) {
|
||||
SV_WORLD.SV_LinkEdict(ent);
|
||||
}
|
||||
|
||||
public void unlinkentity(edict_t ent) {
|
||||
SV_WORLD.SV_UnlinkEdict(ent);
|
||||
}
|
||||
|
||||
// call before removing an interactive edict
|
||||
public int BoxEdicts(float[] mins, float[] maxs, edict_t list[],
|
||||
int maxcount, int areatype) {
|
||||
return SV_WORLD.SV_AreaEdicts(mins, maxs, list, maxcount, areatype);
|
||||
}
|
||||
|
||||
public void Pmove(pmove_t pmove) {
|
||||
PMove.Pmove(pmove);
|
||||
}
|
||||
|
||||
// player movement code common with client prediction
|
||||
// network messaging
|
||||
public void multicast(float[] origin, int to) {
|
||||
SV_SEND.SV_Multicast(origin, to);
|
||||
}
|
||||
|
||||
public void unicast(edict_t ent, boolean reliable) {
|
||||
SV_GAME.PF_Unicast(ent, reliable);
|
||||
}
|
||||
|
||||
|
||||
public void WriteByte(int c) {
|
||||
SV_GAME.PF_WriteByte(c);
|
||||
}
|
||||
|
||||
public void WriteShort(int c) {
|
||||
SV_GAME.PF_WriteShort(c);
|
||||
}
|
||||
|
||||
public void WriteString(String s) {
|
||||
SV_GAME.PF_WriteString(s);
|
||||
}
|
||||
|
||||
public void WritePosition(float[] pos) {
|
||||
SV_GAME.PF_WritePos(pos);
|
||||
}
|
||||
|
||||
// some fractional bits
|
||||
public void WriteDir(float[] pos) {
|
||||
SV_GAME.PF_WriteDir(pos);
|
||||
}
|
||||
|
||||
// console variable interaction
|
||||
public cvar_t cvar(String var_name, String value, int flags) {
|
||||
return Cvar.Get(var_name, value, flags);
|
||||
}
|
||||
|
||||
// console variable interaction
|
||||
public cvar_t cvar_set(String var_name, String value) {
|
||||
return Cvar.Set(var_name, value);
|
||||
}
|
||||
|
||||
// console variable interaction
|
||||
public cvar_t cvar_forceset(String var_name, String value) {
|
||||
return Cvar.ForceSet(var_name, value);
|
||||
}
|
||||
|
||||
// ClientCommand and ServerCommand parameter access
|
||||
public int argc() {
|
||||
return Cmd.Argc();
|
||||
}
|
||||
|
||||
|
||||
public String argv(int n) {
|
||||
return Cmd.Argv(n);
|
||||
}
|
||||
|
||||
// concatenation of all argv >= 1
|
||||
public String args() {
|
||||
return Cmd.Args();
|
||||
}
|
||||
|
||||
// add commands to the server console as if they were typed in
|
||||
// for map changing, etc
|
||||
public void AddCommandString(String text) {
|
||||
Cbuf.AddText(text);
|
||||
}
|
||||
|
||||
}
|
||||
104
src/main/java/lwjake2/game/game_locals_t.java
Normal file
104
src/main/java/lwjake2/game/game_locals_t.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.qcommon.Com;
|
||||
import lwjake2.util.QuakeFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
public class game_locals_t {
|
||||
//
|
||||
// this structure is left intact through an entire game
|
||||
// it should be initialized at dll load time, and read/written to
|
||||
// the server.ssv file for savegames
|
||||
//
|
||||
|
||||
public String helpmessage1 = "";
|
||||
|
||||
public String helpmessage2 = "";
|
||||
|
||||
public int helpchanged; // flash F1 icon if non 0, play sound
|
||||
|
||||
// and increment only if 1, 2, or 3
|
||||
|
||||
public gclient_t clients[] = new gclient_t[Defines.MAX_CLIENTS];
|
||||
|
||||
// can't store spawnpoint in level, because
|
||||
// it would get overwritten by the savegame restore
|
||||
public String spawnpoint = ""; // needed for coop respawns
|
||||
|
||||
// store latched cvars here that we want to get at often
|
||||
public int maxclients;
|
||||
|
||||
public int maxentities;
|
||||
|
||||
// cross level triggers
|
||||
public int serverflags;
|
||||
|
||||
// items
|
||||
public int num_items;
|
||||
|
||||
public boolean autosaved;
|
||||
|
||||
/** Reads the game locals from a file. */
|
||||
public void load(QuakeFile f) throws IOException {
|
||||
f.readString(); // Reads date?
|
||||
|
||||
helpmessage1 = f.readString();
|
||||
helpmessage2 = f.readString();
|
||||
|
||||
helpchanged = f.readInt();
|
||||
// gclient_t*
|
||||
|
||||
spawnpoint = f.readString();
|
||||
maxclients = f.readInt();
|
||||
maxentities = f.readInt();
|
||||
serverflags = f.readInt();
|
||||
num_items = f.readInt();
|
||||
autosaved = f.readInt() != 0;
|
||||
|
||||
// rst's checker :-)
|
||||
if (f.readInt() != 1928)
|
||||
Com.DPrintf("error in loading game_locals, 1928\n");
|
||||
|
||||
}
|
||||
|
||||
/** Writes the game locals to a file. */
|
||||
public void write(QuakeFile f) throws IOException {
|
||||
f.writeString(new Date().toString());
|
||||
|
||||
f.writeString(helpmessage1);
|
||||
f.writeString(helpmessage2);
|
||||
|
||||
f.writeInt(helpchanged);
|
||||
// gclient_t*
|
||||
|
||||
f.writeString(spawnpoint);
|
||||
f.writeInt(maxclients);
|
||||
f.writeInt(maxentities);
|
||||
f.writeInt(serverflags);
|
||||
f.writeInt(num_items);
|
||||
f.writeInt(autosaved ? 1 : 0);
|
||||
// rst's checker :-)
|
||||
f.writeInt(1928);
|
||||
}
|
||||
}
|
||||
420
src/main/java/lwjake2/game/gclient_t.java
Normal file
420
src/main/java/lwjake2/game/gclient_t.java
Normal file
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lwjake2.util.QuakeFile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Slf4j
|
||||
public class gclient_t {
|
||||
public gclient_t(int index)
|
||||
{
|
||||
this.index = index;
|
||||
}
|
||||
// this structure is cleared on each PutClientInServer(),
|
||||
// except for 'client->pers'
|
||||
|
||||
// known to server
|
||||
public player_state_t ps = new player_state_t(); // communicated by server to clients
|
||||
public int ping;
|
||||
|
||||
// private to game
|
||||
public client_persistant_t pers = new client_persistant_t();
|
||||
public client_respawn_t resp = new client_respawn_t();
|
||||
public pmove_state_t old_pmove = new pmove_state_t(); // for detecting out-of-pmove changes
|
||||
|
||||
public boolean showscores; // set layout stat
|
||||
public boolean showinventory; // set layout stat
|
||||
public boolean showhelp;
|
||||
public boolean showhelpicon;
|
||||
|
||||
public int ammo_index;
|
||||
|
||||
public int buttons;
|
||||
public int oldbuttons;
|
||||
public int latched_buttons;
|
||||
|
||||
public boolean weapon_thunk;
|
||||
|
||||
public gitem_t newweapon;
|
||||
|
||||
// sum up damage over an entire frame, so
|
||||
// shotgun blasts give a single big kick
|
||||
public int damage_armor; // damage absorbed by armor
|
||||
public int damage_parmor; // damage absorbed by power armor
|
||||
public int damage_blood; // damage taken out of health
|
||||
public int damage_knockback; // impact damage
|
||||
public float[] damage_from = { 0, 0, 0 }; // origin for vector calculation
|
||||
|
||||
public float killer_yaw; // when dead, look at killer
|
||||
|
||||
public int weaponstate;
|
||||
public float[] kick_angles = { 0, 0, 0 }; // weapon kicks
|
||||
public float[] kick_origin = { 0, 0, 0 };
|
||||
public float v_dmg_roll, v_dmg_pitch, v_dmg_time; // damage kicks
|
||||
public float fall_time, fall_value; // for view drop on fall
|
||||
public float damage_alpha;
|
||||
public float bonus_alpha;
|
||||
public float[] damage_blend = { 0, 0, 0 };
|
||||
public float[] v_angle = { 0, 0, 0 }; // aiming direction
|
||||
public float bobtime; // so off-ground doesn't change it
|
||||
public float[] oldviewangles = { 0, 0, 0 };
|
||||
public float[] oldvelocity = { 0, 0, 0 };
|
||||
|
||||
public float next_drown_time;
|
||||
public int old_waterlevel;
|
||||
public int breather_sound;
|
||||
|
||||
public int machinegun_shots; // for weapon raising
|
||||
|
||||
// animation vars
|
||||
public int anim_end;
|
||||
public int anim_priority;
|
||||
public boolean anim_duck;
|
||||
public boolean anim_run;
|
||||
|
||||
// powerup timers
|
||||
public float quad_framenum;
|
||||
public float invincible_framenum;
|
||||
public float breather_framenum;
|
||||
public float enviro_framenum;
|
||||
|
||||
public boolean grenade_blew_up;
|
||||
public float grenade_time;
|
||||
public int silencer_shots;
|
||||
public int weapon_sound;
|
||||
|
||||
public float pickup_msg_time;
|
||||
|
||||
public float flood_locktill; // locked from talking
|
||||
public float flood_when[] = new float[10]; // when messages were said
|
||||
public int flood_whenhead; // head pointer for when said
|
||||
|
||||
public float respawn_time; // can respawn when time > this
|
||||
|
||||
public edict_t chase_target; // player we are chasing
|
||||
public boolean update_chase; // need to update chase info?
|
||||
|
||||
public int index;
|
||||
|
||||
/** Clears the game client structure. */
|
||||
public void clear()
|
||||
{
|
||||
ping =0;
|
||||
|
||||
pers = new client_persistant_t();
|
||||
resp = new client_respawn_t();
|
||||
old_pmove = new pmove_state_t();
|
||||
|
||||
showscores = false; // set layout stat
|
||||
showinventory = false; // set layout stat
|
||||
showhelp = false;
|
||||
showhelpicon = false;
|
||||
|
||||
ammo_index = 0;
|
||||
|
||||
buttons = oldbuttons = latched_buttons = 0;
|
||||
weapon_thunk = false;
|
||||
newweapon = null;
|
||||
damage_armor = 0;
|
||||
damage_parmor = 0;
|
||||
damage_blood = 0;
|
||||
damage_knockback = 0;
|
||||
|
||||
killer_yaw = 0;
|
||||
damage_from = new float[3];
|
||||
weaponstate = 0;
|
||||
kick_angles = new float[3];
|
||||
kick_origin = new float[3];
|
||||
v_dmg_roll = v_dmg_pitch = v_dmg_time = 0;
|
||||
fall_time = fall_value = 0;
|
||||
damage_alpha = 0;
|
||||
bonus_alpha = 0;
|
||||
damage_blend = new float[3];
|
||||
v_angle = new float[3];
|
||||
bobtime = 0;
|
||||
|
||||
oldviewangles = new float[3];
|
||||
|
||||
oldvelocity = new float[3];
|
||||
|
||||
next_drown_time = 0;
|
||||
|
||||
old_waterlevel = 0;
|
||||
|
||||
breather_sound = 0;
|
||||
machinegun_shots = 0;
|
||||
|
||||
anim_end = 0;
|
||||
anim_priority = 0;
|
||||
anim_duck = false;
|
||||
anim_run = false;
|
||||
|
||||
// powerup timers
|
||||
quad_framenum = 0;
|
||||
invincible_framenum = 0;
|
||||
breather_framenum = 0;
|
||||
enviro_framenum = 0;
|
||||
|
||||
grenade_blew_up = false;
|
||||
grenade_time = 0;
|
||||
silencer_shots = 0;
|
||||
weapon_sound = 0;
|
||||
|
||||
pickup_msg_time = 0;
|
||||
|
||||
flood_locktill = 0; // locked from talking
|
||||
flood_when = new float[10]; // when messages were said
|
||||
flood_whenhead = 0; // head pointer for when said
|
||||
|
||||
respawn_time = 0; // can respawn when time > this
|
||||
|
||||
chase_target = null; // player we are chasing
|
||||
update_chase = false; // need to update chase info?
|
||||
}
|
||||
|
||||
/** Reads a game client from the file. */
|
||||
public void read(QuakeFile f) throws IOException
|
||||
{
|
||||
|
||||
ps.load(f);
|
||||
|
||||
ping = f.readInt();
|
||||
|
||||
pers.read(f);
|
||||
resp.read(f);
|
||||
|
||||
old_pmove.load(f);
|
||||
|
||||
showscores = f.readInt() != 0;
|
||||
showinventory = f.readInt() != 0;
|
||||
showhelp = f.readInt() != 0;
|
||||
showhelpicon = f.readInt() != 0;
|
||||
ammo_index = f.readInt();
|
||||
|
||||
buttons = f.readInt();
|
||||
oldbuttons = f.readInt();
|
||||
latched_buttons = f.readInt();
|
||||
|
||||
weapon_thunk=f.readInt()!=0;
|
||||
|
||||
newweapon=f.readItem();
|
||||
|
||||
|
||||
damage_armor = f.readInt();
|
||||
damage_parmor = f.readInt();
|
||||
damage_blood = f.readInt();
|
||||
damage_knockback = f.readInt();
|
||||
|
||||
damage_from[0] = f.readFloat();
|
||||
damage_from[1] = f.readFloat();
|
||||
damage_from[2] = f.readFloat();
|
||||
|
||||
killer_yaw = f.readFloat();
|
||||
|
||||
weaponstate = f.readInt();
|
||||
|
||||
kick_angles[0] = f.readFloat();
|
||||
kick_angles[1] = f.readFloat();
|
||||
kick_angles[2] = f.readFloat();
|
||||
|
||||
kick_origin[0] = f.readFloat();
|
||||
kick_origin[1] = f.readFloat();
|
||||
kick_origin[2] = f.readFloat();
|
||||
|
||||
v_dmg_roll = f.readFloat();
|
||||
v_dmg_pitch = f.readFloat();
|
||||
v_dmg_time = f.readFloat();
|
||||
fall_time = f.readFloat();
|
||||
fall_value = f.readFloat();
|
||||
damage_alpha = f.readFloat();
|
||||
bonus_alpha = f.readFloat();
|
||||
|
||||
damage_blend[0] = f.readFloat();
|
||||
damage_blend[1] = f.readFloat();
|
||||
damage_blend[2] = f.readFloat();
|
||||
|
||||
v_angle[0] = f.readFloat();
|
||||
v_angle[1] = f.readFloat();
|
||||
v_angle[2] = f.readFloat();
|
||||
|
||||
bobtime = f.readFloat();
|
||||
|
||||
oldviewangles[0] = f.readFloat();
|
||||
oldviewangles[1] = f.readFloat();
|
||||
oldviewangles[2] = f.readFloat();
|
||||
|
||||
oldvelocity[0] = f.readFloat();
|
||||
oldvelocity[1] = f.readFloat();
|
||||
oldvelocity[2] = f.readFloat();
|
||||
|
||||
next_drown_time = f.readFloat();
|
||||
|
||||
old_waterlevel = f.readInt();
|
||||
breather_sound = f.readInt();
|
||||
machinegun_shots = f.readInt();
|
||||
anim_end = f.readInt();
|
||||
anim_priority = f.readInt();
|
||||
anim_duck = f.readInt() != 0;
|
||||
anim_run = f.readInt() != 0;
|
||||
|
||||
quad_framenum = f.readFloat();
|
||||
invincible_framenum = f.readFloat();
|
||||
breather_framenum = f.readFloat();
|
||||
enviro_framenum = f.readFloat();
|
||||
|
||||
grenade_blew_up = f.readInt() != 0;
|
||||
grenade_time = f.readFloat();
|
||||
silencer_shots = f.readInt();
|
||||
weapon_sound = f.readInt();
|
||||
pickup_msg_time = f.readFloat();
|
||||
flood_locktill = f.readFloat();
|
||||
flood_when[0] = f.readFloat();
|
||||
flood_when[1] = f.readFloat();
|
||||
flood_when[2] = f.readFloat();
|
||||
flood_when[3] = f.readFloat();
|
||||
flood_when[4] = f.readFloat();
|
||||
flood_when[5] = f.readFloat();
|
||||
flood_when[6] = f.readFloat();
|
||||
flood_when[7] = f.readFloat();
|
||||
flood_when[8] = f.readFloat();
|
||||
flood_when[9] = f.readFloat();
|
||||
flood_whenhead = f.readInt();
|
||||
respawn_time = f.readFloat();
|
||||
chase_target = f.readEdictRef();
|
||||
update_chase = f.readInt() != 0;
|
||||
|
||||
if (f.readInt() != 8765)
|
||||
log.error("game client load failed for num={}", index);
|
||||
}
|
||||
|
||||
/** Writes a game_client_t (a player) to a file. */
|
||||
public void write(QuakeFile f) throws IOException
|
||||
{
|
||||
ps.write(f);
|
||||
|
||||
f.writeInt(ping);
|
||||
|
||||
pers.write(f);
|
||||
resp.write(f);
|
||||
|
||||
old_pmove.write(f);
|
||||
|
||||
f.writeInt(showscores?1:0);
|
||||
f.writeInt(showinventory?1:0);
|
||||
f.writeInt(showhelp?1:0);
|
||||
f.writeInt(showhelpicon?1:0);
|
||||
f.writeInt(ammo_index);
|
||||
|
||||
f.writeInt(buttons);
|
||||
f.writeInt(oldbuttons);
|
||||
f.writeInt(latched_buttons);
|
||||
|
||||
f.writeInt(weapon_thunk?1:0);
|
||||
f.writeItem(newweapon);
|
||||
|
||||
|
||||
f.writeInt(damage_armor);
|
||||
f.writeInt(damage_parmor);
|
||||
f.writeInt(damage_blood);
|
||||
f.writeInt(damage_knockback);
|
||||
|
||||
f.writeFloat(damage_from[0]);
|
||||
f.writeFloat(damage_from[1]);
|
||||
f.writeFloat(damage_from[2]);
|
||||
|
||||
f.writeFloat(killer_yaw);
|
||||
|
||||
f.writeInt(weaponstate);
|
||||
|
||||
f.writeFloat(kick_angles[0]);
|
||||
f.writeFloat(kick_angles[1]);
|
||||
f.writeFloat(kick_angles[2]);
|
||||
|
||||
f.writeFloat(kick_origin[0]);
|
||||
f.writeFloat(kick_origin[1]);
|
||||
f.writeFloat(kick_origin[2]);
|
||||
|
||||
f.writeFloat(v_dmg_roll);
|
||||
f.writeFloat(v_dmg_pitch);
|
||||
f.writeFloat(v_dmg_time);
|
||||
f.writeFloat(fall_time);
|
||||
f.writeFloat(fall_value);
|
||||
f.writeFloat(damage_alpha);
|
||||
f.writeFloat(bonus_alpha);
|
||||
|
||||
f.writeFloat(damage_blend[0]);
|
||||
f.writeFloat(damage_blend[1]);
|
||||
f.writeFloat(damage_blend[2]);
|
||||
|
||||
f.writeFloat(v_angle[0]);
|
||||
f.writeFloat(v_angle[1]);
|
||||
f.writeFloat(v_angle[2]);
|
||||
|
||||
f.writeFloat(bobtime);
|
||||
|
||||
f.writeFloat(oldviewangles[0]);
|
||||
f.writeFloat(oldviewangles[1]);
|
||||
f.writeFloat(oldviewangles[2]);
|
||||
|
||||
f.writeFloat(oldvelocity[0]);
|
||||
f.writeFloat(oldvelocity[1]);
|
||||
f.writeFloat(oldvelocity[2]);
|
||||
|
||||
f.writeFloat(next_drown_time);
|
||||
|
||||
f.writeInt(old_waterlevel);
|
||||
f.writeInt(breather_sound);
|
||||
f.writeInt(machinegun_shots);
|
||||
f.writeInt(anim_end);
|
||||
f.writeInt(anim_priority);
|
||||
f.writeInt(anim_duck?1:0);
|
||||
f.writeInt(anim_run?1:0);
|
||||
|
||||
f.writeFloat(quad_framenum);
|
||||
f.writeFloat(invincible_framenum);
|
||||
f.writeFloat(breather_framenum);
|
||||
f.writeFloat(enviro_framenum);
|
||||
|
||||
f.writeInt(grenade_blew_up?1:0);
|
||||
f.writeFloat(grenade_time);
|
||||
f.writeInt(silencer_shots);
|
||||
f.writeInt(weapon_sound);
|
||||
f.writeFloat(pickup_msg_time);
|
||||
f.writeFloat(flood_locktill);
|
||||
f.writeFloat(flood_when[0]);
|
||||
f.writeFloat(flood_when[1]);
|
||||
f.writeFloat(flood_when[2]);
|
||||
f.writeFloat(flood_when[3]);
|
||||
f.writeFloat(flood_when[4]);
|
||||
f.writeFloat(flood_when[5]);
|
||||
f.writeFloat(flood_when[6]);
|
||||
f.writeFloat(flood_when[7]);
|
||||
f.writeFloat(flood_when[8]);
|
||||
f.writeFloat(flood_when[9]);
|
||||
f.writeInt(flood_whenhead);
|
||||
f.writeFloat(respawn_time);
|
||||
f.writeEdictRef(chase_target);
|
||||
f.writeInt(update_chase?1:0);
|
||||
|
||||
f.writeInt(8765);
|
||||
}
|
||||
}
|
||||
41
src/main/java/lwjake2/game/gitem_armor_t.java
Normal file
41
src/main/java/lwjake2/game/gitem_armor_t.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public class gitem_armor_t {
|
||||
|
||||
public gitem_armor_t(
|
||||
int base_count,
|
||||
int max_count,
|
||||
float normal_protection,
|
||||
float energy_protection,
|
||||
int armor) {
|
||||
this.base_count= base_count;
|
||||
this.max_count= max_count;
|
||||
this.normal_protection= normal_protection;
|
||||
this.energy_protection= energy_protection;
|
||||
this.armor= armor;
|
||||
}
|
||||
|
||||
int base_count;
|
||||
int max_count;
|
||||
float normal_protection;
|
||||
float energy_protection;
|
||||
int armor;
|
||||
}
|
||||
104
src/main/java/lwjake2/game/gitem_t.java
Normal file
104
src/main/java/lwjake2/game/gitem_t.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public class gitem_t {
|
||||
private static int id = 0;
|
||||
|
||||
public gitem_t(int xxx) {
|
||||
index = xxx;
|
||||
}
|
||||
|
||||
public gitem_t(String classname, EntInteractAdapter pickup,
|
||||
ItemUseAdapter use, ItemDropAdapter drop,
|
||||
EntThinkAdapter weaponthink) {
|
||||
}
|
||||
|
||||
public gitem_t(String classname, EntInteractAdapter pickup,
|
||||
ItemUseAdapter use, ItemDropAdapter drop,
|
||||
EntThinkAdapter weaponthink, String pickup_sound,
|
||||
String world_model, int world_model_flags, String view_model,
|
||||
String icon, String pickup_name, int count_width, int quantity,
|
||||
String ammo, int flags, int weapmodel, gitem_armor_t info, int tag,
|
||||
String precaches) {
|
||||
this.classname = classname;
|
||||
this.pickup = pickup;
|
||||
this.use = use;
|
||||
this.drop = drop;
|
||||
this.weaponthink = weaponthink;
|
||||
this.pickup_sound = pickup_sound;
|
||||
this.world_model = world_model;
|
||||
this.world_model_flags = world_model_flags;
|
||||
this.view_model = view_model;
|
||||
this.icon = icon;
|
||||
this.pickup_name = pickup_name;
|
||||
this.count_width = count_width;
|
||||
this.quantity = quantity;
|
||||
this.ammo = ammo;
|
||||
this.flags = flags;
|
||||
this.weapmodel = weapmodel;
|
||||
this.info = info;
|
||||
this.tag = tag;
|
||||
this.precaches = precaches;
|
||||
|
||||
this.index = id++;
|
||||
}
|
||||
|
||||
String classname; // spawning name
|
||||
|
||||
EntInteractAdapter pickup;
|
||||
|
||||
ItemUseAdapter use;
|
||||
|
||||
ItemDropAdapter drop;
|
||||
|
||||
EntThinkAdapter weaponthink;
|
||||
|
||||
String pickup_sound;
|
||||
|
||||
String world_model;
|
||||
|
||||
int world_model_flags;
|
||||
|
||||
String view_model;
|
||||
|
||||
// client side info
|
||||
String icon;
|
||||
|
||||
String pickup_name; // for printing on pickup
|
||||
|
||||
int count_width; // number of digits to display by icon
|
||||
|
||||
int quantity; // for ammo how much, for weapons how much is used per shot
|
||||
|
||||
String ammo; // for weapons
|
||||
|
||||
int flags; // IT_* flags
|
||||
|
||||
int weapmodel; // weapon model index (for weapons)
|
||||
|
||||
Object info;
|
||||
|
||||
int tag;
|
||||
|
||||
String precaches; // string of all models, sounds, and images this item will
|
||||
// use
|
||||
|
||||
public int index;
|
||||
}
|
||||
154
src/main/java/lwjake2/game/level_locals_t.java
Normal file
154
src/main/java/lwjake2/game/level_locals_t.java
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lwjake2.util.QuakeFile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Slf4j
|
||||
public class level_locals_t {
|
||||
// this structure is cleared as each map is entered
|
||||
// it is read/written to the level.sav file for savegames
|
||||
//
|
||||
public int framenum;
|
||||
public float time;
|
||||
|
||||
public String level_name= ""; // the descriptive name (Outer Base, etc)
|
||||
public String mapname= ""; // the server name (base1, etc)
|
||||
public String nextmap= ""; // go here when fraglimit is hit
|
||||
|
||||
// intermission state
|
||||
public float intermissiontime; // time the intermission was started
|
||||
public String changemap;
|
||||
public boolean exitintermission;
|
||||
public float[] intermission_origin= { 0, 0, 0 };
|
||||
public float[] intermission_angle= { 0, 0, 0 };
|
||||
|
||||
public edict_t sight_client; // changed once each frame for coop games
|
||||
|
||||
public edict_t sight_entity;
|
||||
public int sight_entity_framenum;
|
||||
|
||||
public edict_t sound_entity;
|
||||
public int sound_entity_framenum;
|
||||
|
||||
public edict_t sound2_entity;
|
||||
public int sound2_entity_framenum;
|
||||
|
||||
public int pic_health;
|
||||
|
||||
public int total_secrets;
|
||||
public int found_secrets;
|
||||
|
||||
public int total_goals;
|
||||
public int found_goals;
|
||||
|
||||
public int total_monsters;
|
||||
public int killed_monsters;
|
||||
|
||||
public edict_t current_entity; // entity running from G_RunFrame
|
||||
public int body_que; // dead bodies
|
||||
|
||||
public int power_cubes; // ugly necessity for coop
|
||||
|
||||
/** Writes the levellocales to the file. */
|
||||
public void write(QuakeFile f) throws IOException
|
||||
{
|
||||
f.writeInt(framenum);
|
||||
f.writeFloat(time);
|
||||
f.writeString(level_name);
|
||||
f.writeString(mapname);
|
||||
f.writeString(nextmap);
|
||||
f.writeFloat(intermissiontime);
|
||||
f.writeString(changemap);
|
||||
f.writeBoolean(exitintermission);
|
||||
f.writeVector(intermission_origin);
|
||||
f.writeVector(intermission_angle);
|
||||
f.writeEdictRef(sight_client);
|
||||
|
||||
f.writeEdictRef(sight_entity);
|
||||
f.writeInt(sight_entity_framenum);
|
||||
|
||||
f.writeEdictRef(sound_entity);
|
||||
f.writeInt(sound_entity_framenum);
|
||||
f.writeEdictRef(sound2_entity);
|
||||
f.writeInt(sound2_entity_framenum);
|
||||
|
||||
f.writeInt(pic_health);
|
||||
|
||||
f.writeInt(total_secrets);
|
||||
f.writeInt(found_secrets);
|
||||
|
||||
f.writeInt(total_goals);
|
||||
f.writeInt(found_goals);
|
||||
f.writeInt(total_monsters);
|
||||
f.writeInt(killed_monsters);
|
||||
|
||||
f.writeEdictRef(current_entity);
|
||||
f.writeInt(body_que); // dead bodies
|
||||
f.writeInt(power_cubes); // ugly necessity for coop
|
||||
|
||||
// rst's checker :-)
|
||||
f.writeInt(4711);
|
||||
}
|
||||
|
||||
/** Reads the level locals from the file. */
|
||||
public void read(QuakeFile f) throws IOException
|
||||
{
|
||||
framenum = f.readInt();
|
||||
time = f.readFloat();
|
||||
level_name = f.readString();
|
||||
mapname = f.readString();
|
||||
nextmap = f.readString();
|
||||
intermissiontime = f.readFloat();
|
||||
changemap = f.readString();
|
||||
exitintermission = f.readBoolean();
|
||||
intermission_origin = f.readVector();
|
||||
intermission_angle = f.readVector();
|
||||
sight_client = f.readEdictRef();
|
||||
|
||||
sight_entity = f.readEdictRef();
|
||||
sight_entity_framenum = f.readInt();
|
||||
|
||||
sound_entity = f.readEdictRef();
|
||||
sound_entity_framenum = f.readInt();
|
||||
sound2_entity = f.readEdictRef();
|
||||
sound2_entity_framenum = f.readInt();
|
||||
|
||||
pic_health = f.readInt();
|
||||
|
||||
total_secrets = f.readInt();
|
||||
found_secrets = f.readInt();
|
||||
|
||||
total_goals = f.readInt();
|
||||
found_goals = f.readInt();
|
||||
total_monsters = f.readInt();
|
||||
killed_monsters = f.readInt();
|
||||
|
||||
current_entity = f.readEdictRef();
|
||||
body_que = f.readInt(); // dead bodies
|
||||
power_cubes = f.readInt(); // ugly necessity for coop
|
||||
|
||||
// rst's checker :-)
|
||||
if (f.readInt()!= 4711)
|
||||
log.error("error in reading level_locals.");
|
||||
}
|
||||
}
|
||||
27
src/main/java/lwjake2/game/link_t.java
Normal file
27
src/main/java/lwjake2/game/link_t.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public class link_t {
|
||||
public link_t(Object o) {
|
||||
this.o = o;
|
||||
}
|
||||
public link_t prev, next;
|
||||
public Object o;
|
||||
}
|
||||
24
src/main/java/lwjake2/game/mapsurface_t.java
Normal file
24
src/main/java/lwjake2/game/mapsurface_t.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package lwjake2.game;
|
||||
|
||||
public class mapsurface_t {
|
||||
public csurface_t c = new csurface_t();
|
||||
public String rname;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user