/* * 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 java.awt.Graphics; import java.awt.image.BufferedImage; import java.lang.reflect.Constructor; import java.util.Collection; import java.util.Comparator; import java.util.IdentityHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; public abstract class Sprite { public final Resource res; public final Owner owner; public static List<Factory> factories = new LinkedList<Factory>(); static { factories.add(AnimSprite.fact); factories.add(StaticSprite.fact); } public static final Comparator<Part> partcmp = new Comparator<Part>() { public int compare(Part a, Part b) { if (a.z != b.z) return (a.z - b.z); if (a.cc.y != b.cc.y) return (a.cc.y - b.cc.y); return ((a.subz + a.szo) - (b.subz + b.szo)); } }; public static final Comparator<Part> partidcmp = new Comparator<Part>() { private int eid = 0; private Map<Part, Integer> emergency = null; public int compare(Part a, Part b) { int c = partcmp.compare(a, b); if (c != 0) return (c); c = System.identityHashCode(a) - System.identityHashCode(b); if (c != 0) return (c); if (a == b) return (0); if (emergency == null) { System.err.println("Could not impose ordering on distinct sprite parts, invoking emergency protocol!"); emergency = new IdentityHashMap<Part, Integer>(); } int ai, bi; if (emergency.containsKey(a)) ai = emergency.get(a); else emergency.put(a, ai = eid++); if (emergency.containsKey(a)) bi = emergency.get(a); else emergency.put(b, bi = eid++); return (ai - bi); } }; public interface Drawer { public void addpart(Part p); } public interface Owner { public Random mkrandoom(); public Resource.Neg getneg(); } public static class FactMaker implements Resource.PublishedCode.Instancer { public FactMaker() { } public Factory make(Class<?> cl) throws InstantiationException, IllegalAccessException { if (Factory.class.isAssignableFrom(cl)) return (cl.asSubclass(Factory.class).newInstance()); if (Sprite.class.isAssignableFrom(cl)) return (new DynFactory(cl.asSubclass(Sprite.class))); return (null); } } @Resource.PublishedCode(name = "spr", instancer = FactMaker.class) public interface Factory { public Sprite create(Owner owner, Resource res, Message sdt); } public static class DynFactory implements Factory { private final Class<? extends Sprite> cl; public DynFactory(Class<? extends Sprite> cl) { this.cl = cl; } public Sprite create(Owner owner, Resource res, Message sdt) { try { try { Constructor<? extends Sprite> m = cl.getConstructor(Owner.class, Resource.class); return (m.newInstance(owner, res)); } catch (NoSuchMethodException e) { } try { Constructor<? extends Sprite> m = cl.getConstructor(Owner.class, Resource.class, Message.class); return (m.newInstance(owner, res, sdt)); } catch (NoSuchMethodException e) { } throw (new ResourceException("Cannot call sprite code of dynamic resource", res)); } catch (IllegalAccessException e) { throw (new ResourceException("Cannot call sprite code of dynamic resource", e, res)); } catch (java.lang.reflect.InvocationTargetException e) { throw (new ResourceException("Sprite code of dynamic resource threw an exception", e.getCause(), res)); } catch (InstantiationException e) { throw (new ResourceException("Cannot call sprite code of dynamic resource", e, res)); } } } public static abstract class Part { public Coord cc, off; public Coord ul = Coord.z, lr = Coord.z; public int z, subz, szo; public Effect effect; public Owner owner; public static interface Effect { public GOut apply(GOut in); } public Part(int z) { this.z = z; this.subz = 0; } public Part(int z, int subz) { this.z = z; this.subz = subz; } public Coord sc() { return (cc.add(off)); } public void setup(Coord cc, Coord off) { ul = lr = this.cc = cc; this.off = off; } public boolean checkhit(Coord c) { return (false); } public abstract void draw(BufferedImage buf, Graphics g); public abstract void draw(GOut g); public void drawol(GOut g) { } } public static class ResourceException extends RuntimeException { public Resource res; public ResourceException(String msg, Resource res) { super(msg + " (" + res + ", from " + res.source + ")"); this.res = res; } public ResourceException(String msg, Throwable cause, Resource res) { super(msg + " (" + res + ", from " + res.source + ")", cause); this.res = res; } } protected Sprite(Owner owner, Resource res) { this.res = res; this.owner = owner; } public static Sprite create(Owner owner, Resource res, Message sdt) { if (res.loading) throw (new RuntimeException("Attempted to create sprite on still loading resource")); Resource.CodeEntry e = res.layer(Resource.CodeEntry.class); if (e != null) { try { return (e.get(Factory.class).create(owner, res, sdt)); } catch (RuntimeException exc) { throw (new ResourceException("Error in sprite creation routine for " + res, exc, res)); } } for (Factory f : factories) { Sprite ret = f.create(owner, res, sdt); if (ret != null) return (ret); } throw (new ResourceException("Does not know how to draw resource " + res.name, res)); } public abstract boolean checkhit(Coord c); public abstract void setup(Drawer d, Coord cc, Coord off); public boolean tick(int dt) { return (false); } public abstract Object stateid(); public static void setup(Collection<? extends Part> parts, Drawer d, Coord cc, Coord off) { for (Part p : parts) { p.setup(cc, off); d.addpart(p); } } }