/* * 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. * */ // Created on 04.11.2003 by RST. // $Id: edict_t.java,v 1.6 2004-09-22 19:22:01 salomo Exp $ package jake2.game; import java.io.IOException; import java.io.RandomAccessFile; import jake2.*; import jake2.util.*; 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 set(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); 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) System.err.println("ent load check failed for num " + index); } }