/*
* 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 static haven.ItemInfo.find;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Map;
public class WItem extends Widget implements DTarget {
public static final Resource missing = Resource.load("gfx/invobjs/missing");
private static final Coord hsz = new Coord(24, 24);//Inventory.sqsz.div(2);
private static final Color MATCH_COLOR = new Color(96, 255, 255, 128);
public static final Color CARAT_COLOR = new Color(192, 160, 0);
public final GItem item;
private Tex ltex = null;
private Tex mask = null;
private Resource cmask = null;
private long ts = 0;
private long gobbleUpdateTime = 0;
public WItem(Coord c, Widget parent, GItem item) {
super(c, Inventory.sqsz, parent);
this.item = item;
}
private static Coord upsize(Coord sz) {
int w = sz.x, h = sz.y;
if((w % Inventory.sqsz.x) != 0)
w = Inventory.sqsz.x * ((w / Inventory.sqsz.x) + 1);
if((h % Inventory.sqsz.y) != 0)
h = Inventory.sqsz.y * ((h / Inventory.sqsz.y) + 1);
return(new Coord(w, h));
}
public void drawmain(GOut g, Tex tex) {
g.image(tex, Coord.z);
if(tex != ltex) {
resize(upsize(tex.sz()));
ltex = tex;
}
}
public static BufferedImage rendershort(List<ItemInfo> info) {
ItemInfo.Name nm = find(ItemInfo.Name.class, info);
if(nm == null)
return(null);
BufferedImage img = nm.str.img;
Alchemy ch = find(Alchemy.class, info);
if(ch != null)
img = ItemInfo.catimgsh(5, img, ch.smallmeter(),
Text.std.renderf("(%d%% pure)", (int) (ch.a[0] * 100)).img);
return(img);
}
public static BufferedImage shorttip(List<ItemInfo> info) {
BufferedImage img = rendershort(info);
ItemInfo.Contents cont = find(ItemInfo.Contents.class, info);
if(cont != null) {
BufferedImage rc = rendershort(cont.sub);
if((img != null) && (rc != null))
img = ItemInfo.catimgs(0, img, rc);
else if((img == null) && (rc != null))
img = rc;
}
if(img == null)
return(null);
return(img);
}
public static BufferedImage longtip(GItem item, List<ItemInfo> info) {
BufferedImage img = ItemInfo.longtip(info);
Resource.Pagina pg = item.res.get().layer(Resource.pagina);
if(pg != null)
img = ItemInfo.catimgs(5, img, RichText.render(pg.text, 200).img);
return(img);
}
public BufferedImage longtip(List<ItemInfo> info) {
return(longtip(item, info));
}
public class ItemTip implements Indir<Tex> {
private final TexI tex;
public ItemTip(BufferedImage img) {
if(img == null)
throw(new Loading());
tex = new TexI(img);
}
public GItem item() {
return(item);
}
public Tex get() {
return(tex);
}
}
public class ShortTip extends ItemTip {
public ShortTip(List<ItemInfo> info) {super(shorttip(info));}
}
public class LongTip extends ItemTip {
public LongTip(List<ItemInfo> info) {super(longtip(info));}
}
private long hoverstart;
private ItemTip shorttip = null, longtip = null;
private List<ItemInfo> ttinfo = null;
public Object tooltip(Coord c, Widget prev) {
long now = System.currentTimeMillis();
if (prev != this) {
if(prev instanceof WItem) {
long ps = ((WItem)prev).hoverstart;
if(now - ps < 1000)
hoverstart = now;
else
hoverstart = ps;
} else {
hoverstart = now;
}
}
try {
if(item == null){return "...";}
List<ItemInfo> info = item.info();
if(info.size() < 1)
return(null);
if(info != ttinfo) {
shorttip = longtip = null;
ttinfo = info;
}
if(now - hoverstart < 1000) {
if(shorttip == null)
shorttip = new ShortTip(info);
return(shorttip);
} else {
if((longtip == null) || ts < GItem.infoUpdated){
ts = GItem.infoUpdated;
longtip = new LongTip(info);
}
return(longtip);
}
} catch(Loading e) {
return("...");
}
}
public abstract class AttrCache<T> {
private List<ItemInfo> forinfo = null;
private T save = null;
public T get() {
try {
List<ItemInfo> info = item.info();
if(info != forinfo || save == null) {
save = find(info);
forinfo = info;
}
} catch(Loading e) {
return(null);
}
return(save);
}
public void reset(){
save = null;
}
protected abstract T find(List<ItemInfo> info);
}
public final AttrCache<Color> olcol = new AttrCache<Color>() {
protected Color find(List<ItemInfo> info) {
GItem.ColorInfo cinf = ItemInfo.find(GItem.ColorInfo.class, info);
return((cinf == null)?null:cinf.olcol());
}
};
public final AttrCache<Tex> itemnum = new AttrCache<Tex>() {
protected Tex find(List<ItemInfo> info) {
GItem.NumberInfo ninf = ItemInfo.find(GItem.NumberInfo.class, info);
if(ninf == null) return(null);
return(new TexI(Utils.outline2(Text.render(Integer.toString(ninf.itemnum()), Color.WHITE).img, Color.DARK_GRAY)));
}
};
public final AttrCache<Tex> heurnum = new AttrCache<Tex>() {
protected Tex find(List<ItemInfo> info) {
String num= ItemInfo.getCount(info);
if(num == null) return(null);
return(new TexI(Utils.outline2(Text.render(num, Color.WHITE).img, Color.DARK_GRAY)));
}
};
public final AttrCache<List<Integer>> heurmeter = new AttrCache<List<Integer>>() {
protected List<Integer> find(List<ItemInfo> info) {
return ItemInfo.getMeters(info);
}
};
public final AttrCache<Double> gobblemeter = new AttrCache<Double>() {
protected Double find(List<ItemInfo> info) {
return ItemInfo.getGobbleMeter(info);
}
};
public final AttrCache<String> contentName = new AttrCache<String>() {
protected String find(List<ItemInfo> info) {
return ItemInfo.getContent(info);
}
};
public final AttrCache<Float> carats = new AttrCache<Float>() {
protected Float find(List<ItemInfo> info) {
return ItemInfo.getCarats(info);
}
};
public final AttrCache<Tex> carats_tex = new AttrCache<Tex>() {
protected Tex find(List<ItemInfo> info) {
float c = carats.get();
if(c > 0){
return(new TexI(Utils.outline2(Text.render(String.format("%.2f",c), CARAT_COLOR).img, Color.DARK_GRAY)));
}
return null;
}
};
public void draw(GOut g) {
try {
Resource res = item.res.get();
Tex tex = res.layer(Resource.imgc).tex();
drawmain(g, tex);
draw_highlight(g, res, tex);
if(item.num >= 0) {
g.atext(Integer.toString(item.num), tex.sz(), 1, 1);
} else if(itemnum.get() != null) {
g.aimage(itemnum.get(), tex.sz(), 1, 1);
} else if(carats_tex.get() != null) {
g.aimage(carats_tex.get(), tex.sz(), 1, 1);
} else if(heurnum.get() != null) {
g.aimage(heurnum.get(), tex.sz(), 1, 1);
}
if(item.meter > 0) {
double a = ((double)item.meter) / 100.0;
int r = (int) ((1-a)*255);
int gr = (int) (a*255);
Coord s2 = sz.sub(0, 4);
g.chcolor(r, gr, 0, 255);
Coord bsz = new Coord(4, (int) (a*s2.y));
g.frect(s2.sub(bsz).sub(4,0), bsz);
g.chcolor();
}
checkContents(g);
heurmeters(g);
drawpurity(g);
item.testMatch();
} catch(Loading e) {
missing.loadwait();
g.image(missing.layer(Resource.imgc).tex(), Coord.z, sz);
}
}
private void draw_highlight(GOut g, Resource res, Tex tex) {
Color col = olcol.get();
if(col == null && item.matched && GItem.filter != null){
col = MATCH_COLOR;
}
if(col != null) {
if(cmask != res) {
mask = null;
if(tex instanceof TexI)
mask = ((TexI)tex).mkmask();
cmask = res;
}
if(mask != null) {
g.chcolor(col);
g.image(mask, Coord.z);
g.chcolor();
}
}
}
public final AttrCache<Alchemy> alch = new AttrCache<Alchemy>() {
protected Alchemy find(List<ItemInfo> info) {
Alchemy alch = ItemInfo.find(Alchemy.class, info);
if(alch == null){
ItemInfo.Contents cont = ItemInfo.find(ItemInfo.Contents.class, info);
if(cont == null){return null;}
alch = ItemInfo.find(Alchemy.class, cont.sub);
if(alch == null){return(null);}
}
return alch;
}
};
public final AttrCache<Tex> purity = new AttrCache<Tex>() {
protected Tex find(List<ItemInfo> info) {
Alchemy a = alch.get();
if(a != null) {
String num = String.format("%.2f%%", 100 * a.purity());
Color c = tryGetFoodColor(info, a);
return (new TexI(Utils.outline2(Text.render(num, c).img, Color.DARK_GRAY)));
}
return null;
}
};
public final AttrCache<Tex> puritymult = new AttrCache<Tex>() {
protected Tex find(List<ItemInfo> info) {
Alchemy a = alch.get();
if(a != null) {
String num = String.format("%.2f",1+a.purity());
Color c = tryGetFoodColor(info, a);
return (new TexI(Utils.outline2(Text.render(num, c).img, Color.DARK_GRAY)));
}
return null;
}
};
private Color tryGetFoodColor(List<ItemInfo> info, Alchemy alch)
{
GobbleInfo food = ItemInfo.find(GobbleInfo.class, info);
Color c = alch.color();
if(food!=null)
{
int[] means = new int[4];
int i_highest=-1,i_nexthighest=-1;
for(int b = 0;b<4;b++)
{
means[b]=(food.h[b]+food.l[b])/2;
if(i_highest < 0 || means[i_highest] < means[b])
{
i_nexthighest = i_highest;
i_highest = b;
}
else if(i_nexthighest < 0 || means[i_nexthighest] < means[b])
{
i_nexthighest = b;
}
}
if(means[i_nexthighest] < means[i_highest])
{
c = Tempers.colors[i_highest];
}
}
return c;
}
private void drawpurity(GOut g) {
if(ui.modflags() == 0){return;}//show purity only when any mod key pressed
Tex img = Config.pure_mult?puritymult.get():purity.get();
if(img != null){
g.aimage(img, new Coord(0, sz.y), 0, 1);
}
}
private void checkContents(GOut g) {
if(!Config.show_contents_icons){return;}
String contents = contentName.get();
if(contents == null){ return; }
Tex tex = getContentTex(contents);
if(tex == null){return;}
g.image(tex, Coord.z,hsz);
}
private Tex getContentTex(String contents) {
if(Config.contents_icons == null){ return null;}
String name = null;
for(Map.Entry<String, String> entry : Config.contents_icons.entrySet()) {
if(contents.contains(entry.getKey())){
name = entry.getValue();
break;
}
}
Tex tex = null;
if(name != null){
try {
//return Resource.loadtex(name);
Resource res = Resource.load(name);
tex = new TexI(Utils.outline2(Utils.outline2(res.layer(Resource.imgc).img, Color.BLACK, true), Color.BLACK, true));
} catch (Loading e){
tex = missing.layer(Resource.imgc).tex();
}
}
return tex;
}
private void heurmeters(GOut g) {
Coord c0 = sz.sub(0, 4);
//process for meters in gobble mode
if (Config.gobble_meters && UI.isCursor(UI.Cursor.GOBBLE)) {
Double meter = gobblemeter.get();
if (meter != null && meter > 0) {
draw_meter(g, 0, c0, meter);
}
} else { //process generic meters
List<Integer> meters = heurmeter.get();
if (meters == null) {
return;
}
int k = 0;
for (Integer meter : meters) {
double a = ((double) meter) / 100.0;
draw_meter(g, k, c0, a);
k++;
}
}
}
private void draw_meter(GOut g, int k, Coord c0, double a) {
int r = (int) ((1-a)*255);
int gr = (int) (a*255);
g.chcolor(r, gr, 0, 255);
Coord bsz = new Coord(4, (int) (a*c0.y));
g.frect(new Coord(bsz.x*k+1, c0.y - bsz.y), bsz);
g.chcolor();
}
@Override
public void tick(double dt) {
if(ui.gui.gobble != null && ui.gui.gobble.lastUpdate != gobbleUpdateTime){
gobbleUpdateTime = ui.gui.gobble.lastUpdate;
gobblemeter.reset();
}
super.tick(dt);
}
public boolean mousedown(Coord c, int btn) {
if(checkXfer(btn)) {
return true;
} else if(btn == 1) {
item.wdgmsg("take", c);
return true;
} else if(btn == 3) {
item.wdgmsg("iact", c);
return true;
}
return (false);
}
private boolean checkXfer(int button) {
boolean inv = parent instanceof Inventory;
if(ui.modshift) {
if(ui.modmeta) {
if(inv) {
wdgmsg("transfer-same", item.resname(), button == 3);
return true;
}
} else if(button == 1) {
item.wdgmsg("transfer", c);
return true;
}
} else if(ui.modctrl) {
if(ui.modmeta) {
if(inv) {
wdgmsg("drop-same", item.resname(), button == 3);
return true;
}
} else if(button == 1) {
item.wdgmsg("drop", c);
return true;
}
}
return false;
}
public boolean drop(Coord cc, Coord ul) {
return(false);
}
public boolean iteminteract(Coord cc, Coord ul) {
item.wdgmsg("itemact", ui.modflags());
return(true);
}
}