/* * 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.event.MovementListener; import haven.pathfinder.Node; import java.awt.Color; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; import java.util.TreeMap; public class Gob implements Sprite.Owner { public Coord rc, sc; int clprio = 0; public int id, frame, initdelay = (int) (Math.random() * 3000); public final Glob glob; Map<Class<? extends GAttrib>, GAttrib> attr = new HashMap<Class<? extends GAttrib>, GAttrib>(); public Collection<Overlay> ols = new LinkedList<Overlay>(); public boolean hide; HlFx highlight = null; private boolean isHuman = false; private boolean flagsinit = false; private boolean isHighlight; private boolean isBeast; String beastname; private Node.Type obType; public MovementListener movementListener; public static class Overlay { 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 static interface CDel { public void delete(); } } public static class HlFx implements Sprite.Part.Effect { public long time; public HlFx(long t) { time = t; } public GOut apply(GOut in) { return (new GOut(in) { { chcolor(); } public void chcolor(Color col) { double k = (System.currentTimeMillis() - time) / 1000.0; k = 1 + Math.cos(10 * k); super.chcolor(Utils.blendcol(col, new Color(64, 255, 64, (int) (111 * k)))); } }); } } public Gob(Glob glob, Coord c, int id, int frame) { this.glob = glob; this.rc = c; this.id = id; this.frame = frame; } public Gob(Glob glob, Coord c) { this(glob, c, 0, 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) { if (((getattr(Drawable.class) == null) || (getneg() != null)) && (ol.res.get() != null)) { checkol(ol); ol.spr = Sprite.create(this, ol.res.get(), ol.sdt); } } else { boolean done = ol.spr.tick(dt); if ((!ol.delign || (ol.spr instanceof Overlay.CDel)) && done) i.remove(); } } } public static class DmgInfo { public static final Text.Foundry fnd = new Text.Foundry("SansSerif", 10); private Color col; private int val; public Tex img; public DmgInfo(int c, int value) { this.col = new Color(dup((c & 0xF000) >> 12), dup((c & 0xF00) >> 8), dup((c & 0xF0) >> 4), dup((c & 0xF) >> 0)); ; val = 0; update(value); } public void update(int value) { this.val += value; img = new TexI(Utils.outline2(fnd.render(String.format("%d", val), col).img, Utils.contrast(col))); } private static int dup(int v) { return v << 4 | v; } } public Map<Integer, DmgInfo> dmgmap = new TreeMap<Integer, Gob.DmgInfo>(); private void checkol(Overlay ol) { Resource res = ol.res.get(); if (res == null) { return; } Message msg = ol.sdt; int off = msg.off; if (res.name.indexOf("score") >= 0) { int val = msg.int32(); int j = msg.uint8(); int col = msg.uint16(); // System.out.println(String.format("gob: %d, val: %d, j: %d, col: %d", // id, val, j, col)); if (col != 65535) { DmgInfo inf = dmgmap.get(col); if (inf == null) { inf = new DmgInfo(col, val); dmgmap.put(col, inf); } else { inf.update(val); } } } msg.off = off; } 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 move(Coord c) { Moving m = getattr(Moving.class); if (m != null) m.move(c); this.rc = c; } public Coord getc() { Moving m = getattr(Moving.class); if (m != null) return (m.getc()); else return (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()); 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) { attr.remove(attrclass(c)); } public Coord drawoff() { Coord ret = Coord.z; DrawOffset dro = getattr(DrawOffset.class); if (dro != null) ret = ret.add(dro.off); Following flw = getattr(Following.class); if (flw != null) ret = ret.add(flw.doff); return (ret); } public void checkhide() { } public void drawsetup(Sprite.Drawer drawer, Coord dc, Coord sz) { Resource res = getres(); if (Config.TEST && !dc.isect(Coord.z, sz)) { return; } hide = (res != null) && res.hide && res.once && !res.skiphide && Config.hide; if (hide) return; if (res != null) res.once = true; Drawable d = getattr(Drawable.class); Coord dro = drawoff(); for (Overlay ol : ols) { if (ol.spr != null) { ol.spr.setup(drawer, dc, dro); } } if (d != null) { d.setup(drawer, dc, dro); } } public Resource getres() { Resource res = null; ResDrawable dw = getattr(ResDrawable.class); if (dw != null) { res = dw.res.get(); } else { Layered ld = getattr(Layered.class); if ((ld != null) && (ld.layers.size() > 0)) { res = ld.layers.get(0).get(); } } return res; } public String resname() { Resource res = getres(); String name = ""; if (res != null) { name = res.name; } return name; } public String[] resnames() { List<String> names = new ArrayList<String>(); ResDrawable dw = getattr(ResDrawable.class); Resource res; if (dw != null) { res = dw.res.get(); if (res != null) { names.add(res.name); } } else { Layered ld = getattr(Layered.class); if (ld != null) { for (Indir<Resource> ir : ld.layers) { res = ir.get(); if (res != null) { names.add(res.name); } } } } return names.toArray(new String[names.size()]); } private void initflags() { if (flagsinit) { return; } String name = resname(); if (name.length() == 0) { return; } flagsinit = true; isHighlight = Config.hlcfg.keySet().contains(name); if (isHighlight) { return; } // checking bestiality if (!name.contains("/cdv")) { isBeast = checkBeast(); if (isBeast) { return; } } // checking humanity... if (name.contains("/borka/")) { isHuman = checkHumanity(); } } private boolean checkBeast() { for (String name : resnames()) { for (String pat : Config.beasts.keySet()) { if (name.contains(pat)) { beastname = pat; return true; } } } return false; } private boolean checkHumanity() { for (String name : resnames()) { if (name.contains("/borka/body")) { return true; } } return false; } public boolean isHuman() { initflags(); return isHuman; } public boolean isBeast() { initflags(); return isBeast; } public boolean isHighlight() { initflags(); return isHighlight; } public Random mkrandoom() { if (id < 0) return (MCache.mkrandoom(rc)); else return (new Random(id)); } public Resource.Neg getneg() { Resource r = getres(); if (r != null) { return (r.layer(Resource.negc)); } return (null); } public boolean checkWalking() { // new for (String name : resnames()) { if (name.contains("/walking/")) { return true; } } return false; } public byte getblob(int index) { Drawable d = getattr(Drawable.class); ResDrawable dw = getattr(ResDrawable.class); if (dw != null && d != null) { if (index < dw.sdt.blob.length && index >= 0) return dw.sdt.blob[index]; } return 0; } public Node.Type resolveObType(MapView mv) { if (obType != null) return obType; Resource rsrc = getres(); if (rsrc == null) return Node.Type.NOT_IMPLEMENTED; // remove "gfx/" prefix String resnameStripped = rsrc.name.substring(4); // strip trailing numbers // /terobjs/trees/pine/06 // terobjs/trees/fir/fir06 // also strips 1 from kritter/boat/boat-1 resnameStripped = resnameStripped.replaceAll("\\d*$", ""); // strip trailing direction // terobjs/ridges/grass/e2n // terobjs/ridges/grass/e // terobjs/ridges/grass/es if (!resnameStripped.equals("borka/s")) resnameStripped = resnameStripped.replaceAll("\\/[a-z]?\\d?[a-z]{1}$", ""); // strip walls direction/type // arch/walls/brick-cp // arch/walls/brick-we // arch/walls/fence-cp // arch/gates/fence-ns resnameStripped = resnameStripped.replaceAll("\\-[a-z]{2}$", ""); // strip trailing "/" resnameStripped = resnameStripped.replaceAll("\\/$", ""); if (!Config.obTypes.containsKey(resnameStripped)) obType = Node.Type.NOT_IMPLEMENTED; else obType = Config.obTypes.get(resnameStripped); return obType; } }