/*
* This file is part of the Haven & Hearth game client.
* Copyright (C) 2009 Fredrik Tolf <fredrik@dolda2000.com>, and
* Björn Johannessen <johannessen.bjorn@gmail.com>
*
* Redistribution and/or modification of this file is subject to the
* terms of the GNU Lesser General Public License, version 3, as
* published by the Free Software Foundation.
*
* 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.
*
* Other parts of this source tree adhere to other copying
* rights. Please see the file `COPYING' in the root directory of the
* source tree for details.
*
* A copy the GNU Lesser General Public License is distributed along
* with the source tree of which this file is a part in the file
* `doc/LPGL-3'. If it is missing for any reason, please see the Free
* Software Foundation's website at <http://www.fsf.org/>, or write
* to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package haven;
import haven.minimap.Radar.GobBlink;
import java.util.*;
public class Gob implements Sprite.Owner, Skeleton.ModOwner, Rendered {
public Coord rc, sc;
public Coord3f sczu;
public double a;
public boolean virtual = false;
int clprio = 0;
public long id;
public int frame, initdelay = (int)(Math.random() * 3000) + 3000;
public final Glob glob;
Map<Class<? extends GAttrib>, GAttrib> attr = new HashMap<Class<? extends GAttrib>, GAttrib>();
public Collection<Overlay> ols = new LinkedList<Overlay>();
private GobPath path = null;
public static class Overlay implements Rendered {
public Indir<Resource> res;
public Message sdt;
public Sprite spr;
public int id;
public boolean delign = false;
public Overlay(int id, Indir<Resource> res, Message sdt) {
this.id = id;
this.res = res;
this.sdt = sdt;
spr = null;
}
public Overlay(Sprite spr) {
this.id = -1;
this.res = null;
this.sdt = null;
this.spr = spr;
}
public static interface CDel {
public void delete();
}
public static interface CUpd {
public void update(Message sdt);
}
public static interface SetupMod {
public void setupgob(GLState.Buffer buf);
public void setupmain(RenderList rl);
}
public void draw(GOut g) {}
public boolean setup(RenderList rl) {
if(spr != null)
rl.add(spr, null);
return(false);
}
}
public Gob(Glob glob, Coord c, long id, int frame) {
this.glob = glob;
this.rc = c;
this.id = id;
this.frame = frame;
}
public Gob(Glob glob, Coord c) {
this(glob, c, -1, 0);
}
public static interface ANotif<T extends GAttrib> {
public void ch(T n);
}
public void ctick(int dt) {
int dt2 = dt + initdelay;
initdelay = 0;
for(GAttrib a : attr.values()) {
if(a instanceof Drawable)
a.ctick(dt2);
else
a.ctick(dt);
}
for(Iterator<Overlay> i = ols.iterator(); i.hasNext();) {
Overlay ol = i.next();
if(ol.spr == null) {
try {
ol.sdt.off = 0;
ol.spr = Sprite.create(this, ol.res.get(), ol.sdt);
} catch(Loading e) {}
} else {
boolean done = ol.spr.tick(dt);
if((!ol.delign || (ol.spr instanceof Overlay.CDel)) && done)
i.remove();
}
}
if(virtual && ols.isEmpty())
glob.oc.remove(id);
loc.tick();
}
public Overlay findol(int id) {
for(Overlay ol : ols) {
if(ol.id == id)
return(ol);
}
return(null);
}
public void tick() {
for(GAttrib a : attr.values())
a.tick();
}
public void dispose() {
for(GAttrib a : attr.values())
a.dispose();
}
public void move(Coord c, double a) {
Moving m = getattr(Moving.class);
if(m != null)
m.move(c);
this.rc = c;
this.a = a;
}
public Coord3f getc() {
Moving m = getattr(Moving.class);
if(m != null)
return(m.getc());
else
return(getrc());
}
public Coord3f getrc() {
return(new Coord3f(rc.x, rc.y, glob.map.getcz(rc)));
}
private Class<? extends GAttrib> attrclass(Class<? extends GAttrib> cl) {
while(true) {
Class<?> p = cl.getSuperclass();
if(p == GAttrib.class)
return(cl);
cl = p.asSubclass(GAttrib.class);
}
}
public void setattr(GAttrib a) {
Class<? extends GAttrib> ac = attrclass(a.getClass());
if (Config.gobpath) {
if (ac == Moving.class) {
if (path == null) {
path = new GobPath(this);
ols.add(new Overlay(path));
}
path.move((Moving) a);
}
}
attr.put(ac, a);
}
public <C extends GAttrib> C getattr(Class<C> c) {
GAttrib attr = this.attr.get(attrclass(c));
if(!c.isInstance(attr))
return(null);
return(c.cast(attr));
}
public void delattr(Class<? extends GAttrib> c) {
Class<? extends GAttrib> aClass = attrclass(c);
attr.remove(aClass);
if(aClass == Moving.class && path != null) {
path.stop();
}
}
public void draw(GOut g) {}
public boolean setup(RenderList rl) {
for(Overlay ol : ols)
rl.add(ol, null);
for(Overlay ol : ols) {
if(ol.spr instanceof Overlay.SetupMod)
((Overlay.SetupMod)ol.spr).setupmain(rl);
}
GobHealth hlt = getattr(GobHealth.class);
if(hlt != null)
rl.prepc(hlt.getfx());
if(Config.blink){
GobBlink blnk = getattr(GobBlink.class);
if(blnk != null && blnk.visible())
rl.prepc(blnk.getfx());
}
GobHighlight highlight = getattr(GobHighlight.class);
if(highlight != null){
if(highlight.duration > 0) {
rl.prepc(highlight.getfx());
} else {
delattr(GobHighlight.class);
}
}
Drawable d = getattr(Drawable.class);
if(d != null)
d.setup(rl);
Speaking sp = getattr(Speaking.class);
if(sp != null)
rl.add(sp.fx, null);
KinInfo ki = getattr(KinInfo.class);
if(ki != null)
rl.add(ki.fx, null);
return(false);
}
public Random mkrandoom() {
return(new Random(id));
}
public Resource.Neg getneg() {
Drawable d = getattr(Drawable.class);
if(d != null)
return(d.getneg());
return(null);
}
public Glob glob() {
return(glob);
}
/* Because generic functions are too nice a thing for Java. */
public double getv() {
Moving m = getattr(Moving.class);
if(m == null)
return(0);
return(m.getv());
}
public final GLState olmod = new GLState() {
public void apply(GOut g) {}
public void unapply(GOut g) {}
public void prep(Buffer buf) {
for(Overlay ol : ols) {
if(ol.spr instanceof Overlay.SetupMod) {
((Overlay.SetupMod)ol.spr).setupgob(buf);
}
}
}
};
public static final GLState.Slot<Save> savepos = new GLState.Slot<Save>(GLState.Slot.Type.SYS, Save.class, PView.loc);
public class Save extends GLState {
public Matrix4f cam = new Matrix4f(), wxf = new Matrix4f(),
mv = new Matrix4f();
public Projection proj = null;
public void apply(GOut g) {
mv.load(cam.load(g.st.cam)).mul1(wxf.load(g.st.wxf));
Projection proj = g.st.cur(PView.proj);
Coord3f s = proj.toscreen(mv.mul4(Coord3f.o), g.sz);
Gob.this.sc = new Coord(s);
Gob.this.sczu = proj.toscreen(mv.mul4(Coord3f.zu), g.sz).sub(s);
this.proj = proj;
}
public void unapply(GOut g) {}
public void prep(Buffer buf) {
buf.put(savepos, this);
}
}
public final Save save = new Save();
public class GobLocation extends Location {
public Coord3f c = null;
private double a = 0.0;
private Matrix4f update = null;
public GobLocation() {
super(Matrix4f.id);
}
public void tick() {
try {
Coord3f c = getc();
c.y = -c.y;
if((this.c == null) || !c.equals(this.c) || (this.a != Gob.this.a)) {
update(makexlate(new Matrix4f(), this.c = c)
.mul1(makerot(new Matrix4f(), Coord3f.zu, (float)-(this.a = Gob.this.a))));
}
} catch(Loading l) {}
}
public Location freeze() {
return(new Location(fin(Matrix4f.id)));
}
}
public final GobLocation loc = new GobLocation();
}