/* * 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.Color; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Observable; import java.util.Set; import java.util.TreeMap; import java.util.WeakHashMap; import org.ender.timer.Timer; public class Glob { public static final int GMSG_TIME = 0; public static final int GMSG_ASTRO = 1; public static final int GMSG_LIGHT = 2; public static final int GMSG_SKY = 3; public static final float MAX_BRIGHT = 0.62f; public long time, epoch = System.currentTimeMillis(); public int season; public OCache oc = new OCache(this); public MCache map; public Session sess; public Party party; public Set<Pagina> paginae = new HashSet<Pagina>(); public int pagseq = 0; public Map<Resource, Pagina> pmap = new WeakHashMap<Resource, Pagina>(); public Map<String, CAttr> cattr = new HashMap<String, CAttr>(); public Map<Integer, Buff> buffs = new TreeMap<Integer, Buff>(); public Color lightamb = null, lightdif = null, lightspc = null; public Color olightamb = null, olightdif = null, olightspc = null; public Color tlightamb = null, tlightdif = null, tlightspc = null; public double lightang = 0.0, lightelev = 0.0; public double olightang = 0.0, olightelev = 0.0; public double tlightang = 0.0, tlightelev = 0.0; public long lchange = -1; public Indir<Resource> sky1 = null, sky2 = null; public double skyblend = 0.0; public java.awt.Color origamb = null; public long cattr_lastupdate = 0; public Glob(Session sess) { this.sess = sess; map = new MCache(sess); party = new Party(this); } public static class CAttr extends Observable { String nm; int base, comp; public CAttr(String nm, int base, int comp) { this.nm = nm.intern(); this.base = base; this.comp = comp; } public void update(int base, int comp) { if((base == this.base) && (comp == this.comp)) return; Integer old = this.comp; this.base = base; this.comp = comp; setChanged(); notifyObservers(old); } } public static class Pagina implements java.io.Serializable { private final Resource res; public State st; public int meter, dtime; public long gettime; public Image img; public int newp; public long fstart; /* XXX: ABUSAN!!! */ public interface Image { public Tex tex(); } public static enum State { ENABLED, DISABLED { public Image img(final Pagina pag) { return(new Image() { private Tex c = null; public Tex tex() { if(pag.res() == null) return(null); if(c == null) c = new TexI(PUtils.monochromize(pag.res().layer(Resource.imgc).img, Color.LIGHT_GRAY)); return(c); } }); } }; public Image img(final Pagina pag) { return(new Image() { public Tex tex() { if(pag.res() == null) return(null); return(pag.res().layer(Resource.imgc).tex()); } }); } } public Pagina(Resource res) { this.res = res; state(State.ENABLED); } public Resource res() { return(res); } public Resource.AButton act() { if(res().loading) return(null); return(res().layer(Resource.action)); } public void state(State st) { this.st = st; this.img = st.img(this); } } private static Color colstep(Color o, Color t, double a) { int or = o.getRed(), og = o.getGreen(), ob = o.getBlue(), oa = o.getAlpha(); int tr = t.getRed(), tg = t.getGreen(), tb = t.getBlue(), ta = t.getAlpha(); return(new Color(or + (int)((tr - or) * a), og + (int)((tg - og) * a), ob + (int)((tb - ob) * a), oa + (int)((ta - oa) * a))); } private void ticklight(int dt) { if(lchange >= 0) { lchange += dt; if(lchange > 2000) { lchange = -1; origamb = tlightamb; lightdif = tlightdif; lightspc = tlightspc; lightang = tlightang; lightelev = tlightelev; } else { double a = lchange / 2000.0; origamb = colstep(olightamb, tlightamb, a); lightdif = colstep(olightdif, tlightdif, a); lightspc = colstep(olightspc, tlightspc, a); lightang = olightang + a * Utils.cangle(tlightang - olightang); lightelev = olightelev + a * Utils.cangle(tlightelev - olightelev); } brighten(); } } private long lastctick = 0; public void ctick() { long now = System.currentTimeMillis(); int dt; if(lastctick == 0) dt = 0; else dt = (int)(now - lastctick); dt = Math.max(dt, 0); synchronized(this) { ticklight(dt); } oc.ctick(dt); map.ctick(dt); lastctick = now; } private static double defix(int i) { return(((double)i) / 1e9); } private long lastrep = 0; private long rgtime = 0; public long globtime() { long now = System.currentTimeMillis(); long raw = ((now - epoch) * 3) + (time * 1000); if(lastrep == 0) { rgtime = raw; } else { long gd = (now - lastrep) * 3; rgtime += gd; if(Math.abs(rgtime + gd - raw) > 1000) rgtime = rgtime + (long)((raw - rgtime) * (1.0 - Math.pow(10.0, -(now - lastrep) / 1000.0))); } lastrep = now; return(rgtime); } public void blob(Message msg) { boolean inc = msg.uint8() != 0; while(!msg.eom()) { int t = msg.uint8(); switch(t) { case GMSG_TIME: time = msg.int32(); season = msg.uint8(); epoch = System.currentTimeMillis(); if(!inc) lastrep = 0; Timer.server = 1000*time; Timer.local = System.currentTimeMillis(); break; case GMSG_LIGHT: synchronized(this) { tlightamb = msg.color(); tlightdif = msg.color(); tlightspc = msg.color(); tlightang = (msg.int32() / 1000000.0) * Math.PI * 2.0; tlightelev = (msg.int32() / 1000000.0) * Math.PI * 2.0; if(inc) { olightamb = origamb; olightdif = lightdif; olightspc = lightspc; olightang = lightang; olightelev = lightelev; lchange = 0; } else { origamb = tlightamb; lightdif = tlightdif; lightspc = tlightspc; lightang = tlightang; lightelev = tlightelev; lchange = -1; } brighten(); } break; case GMSG_SKY: int id1 = msg.uint16(); if(id1 == 65535) { synchronized(this) { sky1 = sky2 = null; skyblend = 0.0; } } else { int id2 = msg.uint16(); if(id2 == 65535) { synchronized(this) { sky1 = sess.getres(id1); sky2 = null; skyblend = 0.0; } } else { synchronized(this) { sky1 = sess.getres(id1); sky2 = sess.getres(id2); skyblend = msg.int32() / 1000000.0; } } } break; default: throw(new RuntimeException("Unknown globlob type: " + t)); } } } public synchronized void brighten() { float hsb[] = Color.RGBtoHSB(origamb.getRed(), origamb.getGreen(), origamb.getBlue(), null); float b = hsb[2]; if(b < MAX_BRIGHT){ hsb[2] = b + Config.brighten*(MAX_BRIGHT - b); } lightamb = Color.getHSBColor(hsb[0], hsb[1], hsb[2]); DarknessWnd.update(); } public Pagina paginafor(Resource res) { if(res == null) return(null); synchronized(pmap) { Pagina p = pmap.get(res); if(p == null) pmap.put(res, p = new Pagina(res)); return(p); } } public void paginae(Message msg) { synchronized(paginae) { while(!msg.eom()) { int act = msg.uint8(); if(act == '+') { String nm = msg.string(); int ver = msg.uint16(); final Pagina pag = paginafor(Resource.load(nm, ver)); paginae.add(pag); pag.state(Pagina.State.ENABLED); pag.meter = 0; int t; while((t = msg.uint8()) != 0) { if(t == '!') { pag.state(Pagina.State.DISABLED); } else if(t == '*') { pag.meter = msg.int32(); pag.gettime = System.currentTimeMillis(); pag.dtime = msg.int32(); } else if(t == '^') { pag.newp = 1; Utils.defer(new Runnable() { @Override public void run() { pag.res().loadwait(); String name = pag.res().layer(Resource.action).name; UI.instance.message(String.format("You gain access to '%s'!", name), GameUI.MsgType.INFO); } }); } } } else if(act == '-') { String nm = msg.string(); int ver = msg.uint16(); paginae.remove(paginafor(Resource.load(nm, ver))); } } pagseq++; } } public void cattr(Message msg) { synchronized(cattr) { while(!msg.eom()) { String nm = msg.string(); int base = msg.int32(); int comp = msg.int32(); CAttr a = cattr.get(nm); if(a == null) { a = new CAttr(nm, base, comp); cattr.put(nm, a); } else { a.update(base, comp); } if(nm.equals("carry")){ GameUI gui = UI.instance.gui; if(gui != null){ gui.uimsg("weight", gui.weight); } } } } cattr_lastupdate = System.currentTimeMillis(); } public void buffmsg(Message msg) { String name = msg.string().intern(); synchronized(buffs) { if(name == "clear") { buffs.clear(); } else if(name == "set") { int id = msg.int32(); Indir<Resource> res = sess.getres(msg.uint16()); String tt = msg.string(); int ameter = msg.int32(); int nmeter = msg.int32(); int cmeter = msg.int32(); int cticks = msg.int32(); boolean major = msg.uint8() != 0; Buff buff; if((buff = buffs.get(id)) == null) { buff = new Buff(id, res); } else { buff.res = res; } if(tt.equals("")) buff.tt = null; else buff.tt = tt; buff.ameter = ameter; buff.nmeter = nmeter; buff.ntext = null; buff.cmeter = cmeter; buff.cticks = cticks; buff.major = major; buff.gettime = System.currentTimeMillis(); buffs.put(id, buff); } else if(name == "rm") { int id = msg.int32(); buffs.remove(id); } } } }