public void addpart(Sprite.Part p) {
				p.effect = fx;
				if ((p.ul.x >= sz.x) || (p.ul.y >= sz.y) || (p.lr.x < 0)
						|| (p.lr.y < 0))
					return;
				sprites.add(p);
				p.owner = cur;
				p.szo = szo;
			}
		}
		
		//Kerri
		if(KerriUtils.iObj.size() > 0) {
			g.chcolor(20, 20, 250, 108);
			synchronized (glob.oc) {
				for (Gob gob : glob.oc) {
					if(KerriUtils.iObj.contains(Integer.valueOf(gob.id))) {
						Resource.Neg neg = gob.getneg();
						if (neg == null) {
							continue;
						}
						if ((neg.bs.x > 0) && (neg.bs.y > 0)) {
							Coord c1 = gob.position().add(neg.bc);
							Coord c2 = c1.add(neg.bs);
							g.frect(m2s(c1).add(oc), m2s(new Coord(c2.x, c1.y))
									.add(oc), m2s(c2).add(oc),
									m2s(new Coord(c1.x, c2.y)).add(oc));
						}
					}
				}
			}
			g.chcolor();
		}
		
		if(ui.modctrl) {
			g.chcolor(20, 20, 250, 108);
			synchronized (glob.oc) {
				for (Gob gob : glob.oc) {
					if(gob.id == 0) {
						Resource.Neg neg = gob.getneg();
						if (neg == null) {
							continue;
						}
						if ((neg.bs.x > 0) && (neg.bs.y > 0)) {
							Coord c1 = gob.position().add(neg.bc);
							Coord c2 = c1.add(neg.bs);
							g.frect(m2s(c1).add(oc), m2s(new Coord(c2.x, c1.y))
									.add(oc), m2s(c2).add(oc),
									m2s(new Coord(c1.x, c2.y)).add(oc));
						}
						break;
					}
				}
			}
			g.chcolor();
		}

		if (Config.showHidden && Config.hide) {
			if(!Config.aimacrazyman)
				g.chcolor(Config.hideColor);
			synchronized (glob.oc) {
				for (Gob gob : glob.oc) {
					if(Config.aimacrazyman) {
						Random r = new Random();
						g.chcolor(r.nextInt(255), r.nextInt(255), r.nextInt(255), r.nextInt(255));
					}
					Resource res = gob.getres();
					if (!Config.hide_all) {
						if (!gob.hide || ((res != null) && (res.skiphighlight)))
							continue;
					}
					if (res.name != null && res.name.contains("gfx/arch/sign")) {
						Coord c1 = gob.position();
						Coord c2 = c1.add(new Coord(2, 2));
						g.frect(m2s(c1).add(oc), m2s(new Coord(c2.x, c1.y))
								.add(oc), m2s(c2).add(oc),
								m2s(new Coord(c1.x, c2.y)).add(oc));
					}
					Resource.Neg neg = gob.getneg();
					if (neg == null) {
						continue;
					}
					if ((neg.bs.x > 0) && (neg.bs.y > 0)) {
						Coord c1 = gob.position().add(neg.bc);
						Coord c2 = c1.add(neg.bs);
						g.frect(m2s(c1).add(oc), m2s(new Coord(c2.x, c1.y))
								.add(oc), m2s(c2).add(oc),
								m2s(new Coord(c1.x, c2.y)).add(oc));
					}
				}
			}
			g.chcolor();
		}

		GobMapper drawer = new GobMapper();
		synchronized (glob.oc) {
			for (Gob gob : glob.oc) {
				Integer tmp /*lol*/ = Integer.valueOf(gob.id);
				if(ui.modctrl && gob.id == 0) continue;
				if(KerriUtils.iObj.contains(tmp)) continue;
				Resource res = gob.getres();
				if(res != null) {
					if(res.name.contains("gfx/terobjs/clue")) {
						//scent checker
						LinkedList<Gob.Overlay> olays = (LinkedList<haven.Gob.Overlay>) gob.ols;
						int scent = olays.get(0).sdt.uint16K();
						if(KerriUtils.isAssault(scent) && Config.hideAsslt) continue;
						if(KerriUtils.isTheft(scent) && Config.hideTheft) continue;
						if(KerriUtils.isTresspass(scent) && Config.hideTressp) continue;
						if(KerriUtils.isVandalism(scent) && Config.hideVand) continue;
						if(KerriUtils.isBattery(scent) && Config.hideBatt) continue;
						if(KerriUtils.isMurder(scent) && Config.hideMurd) continue;
						//System.out.println(scent);
					}
				}
				drawer.chcur(gob);
				Coord dc = m2s(gob.position()).add(oc);
				gob.sc = dc;
				gob.drawsetup(drawer, dc, sz);
				Speaking s = gob.getattr(Speaking.class);
				if (s != null)
					speaking.add(s);
				KinInfo k = gob.getattr(KinInfo.class);
				if (k != null)
					kin.add(k);
			}
			if (curf != null)
				curf.tick("setup");
			Collections.sort(sprites, Sprite.partidcmp);
			{
				Sprite.Part[] clickable = new Sprite.Part[sprites.size()];
				for (int o = 0, u = clickable.length - 1; o < clickable.length; o++, u--)
					clickable[u] = sprites.get(o);
				this.clickable = clickable;
			}
			if (curf != null)
				curf.tick("sort");
			//Kerri
			if(pmousepos != null)
				objectUnderMouse = gobatpos(pmousepos);
			else
				objectUnderMouse = null;
			obscured = findobsc();
			if (curf != null)
				curf.tick("obsc");
			for (Sprite.Part part : sprites) {
				if (part.effect != null)
					part.draw(part.effect.apply(g));
				else
					part.draw(g);
			}
			for (Sprite.Part part : obscured) {
				GOut g2 = new GOut(g);
				GobHealth hlt;
				if ((part.owner != null)
						&& (part.owner instanceof Gob)
						&& ((hlt = ((Gob) part.owner).getattr(GobHealth.class)) != null))
					g2.chcolor(255, (int) (hlt.asfloat() * 255), 0, 255);
				else
					g2.chcolor(255, 255, 0, 255);
				part.drawol(g2);
			}

			if (curf != null)
				curf.tick("draw");
			g.image(mask, Coord.z);
			long now = System.currentTimeMillis();
			RootWidget.names_ready = (RootWidget.screenshot && Config.sshot_nonames);
			if (!RootWidget.names_ready) {
				for (KinInfo k : kin) {
					Tex t = k.rendered();
					Coord gc = k.gob.sc;
					String name = k.gob.resname();
					boolean isother = name.contains("hearth")
							|| name.contains("skeleton");
					if (gc.isect(Coord.z, sz)) {
						if (k.seen == 0)
							k.seen = now;
						int tm = (int) (now - k.seen);
						Color show = null;
						boolean auto = (k.type & 1) == 0;
						if ((isother && Config.showOtherNames)
								|| (!isother && Config.showNames)
								|| (k.gob == objectUnderMouse)) {
							show = Color.WHITE;
						} else if (auto && (tm < 7500)) {
							show = Utils.clipcol(255, 255, 255,
									255 - ((255 * tm) / 7500));
						}
						if (show != null) {
							g.chcolor(show);
							g.image(t, gc.add(-t.sz().x / 2, -40 - t.sz().y));
							g.chcolor();
						}
					} else {
						k.seen = 0;
					}
				}
			}
			for (Speaking s : speaking) {
				s.draw(g, s.gob.sc.add(s.off));
			}
			if (curf != null) {
				curf.tick("aux");
				curf.fin();
				curf = null;
			}
			if (Config.show_gob_health) {
				for (Gob gob : glob.oc) {
					GobHealth hlt = gob.getattr(GobHealth.class);
					if (hlt != null) {
						int percent = (int) (hlt.asfloat() * 100);
						if (percent < 100) {
							g.atext(Integer.toString(percent) + "%", gob.sc, 0,
									1);
						}
					}
				}
			}
		}
	}

	public void drawarrows(GOut g) {
		Coord oc = viewoffset(sz, mc);
		Coord hsz = sz.div(2); //half size
		double ca = -Coord.z.angle(hsz);
		for (Party.Member partyMember : glob.party.memb.values()) {
			// Gob gob = glob.oc.getgob(id);
			Coord memberCoords = partyMember.getc();
			if (memberCoords == null)
				continue;
			Coord sc = m2s(memberCoords).add(oc);
			if (!sc.isect(Coord.z, sz)) {
				double a = -hsz.angle(sc);
				Coord ac;
				if ((a > ca) && (a < -ca)) {
					ac = new Coord(sz.x, hsz.y - (int) (Math.tan(a) * hsz.x));
				} else if ((a > -ca) && (a < Math.PI + ca)) {
					ac = new Coord(hsz.x
							- (int) (Math.tan(a - Math.PI / 2) * hsz.y), 0);
				} else if ((a > -Math.PI - ca) && (a < ca)) {
					ac = new Coord(hsz.x
							+ (int) (Math.tan(a + Math.PI / 2) * hsz.y), sz.y);
				} else {
					ac = new Coord(0, hsz.y + (int) (Math.tan(a) * hsz.x));
				}
				g.chcolor(partyMember.col);
				Coord bc = ac.add(Coord.sc(a, -10));
				g.line(bc, bc.add(Coord.sc(a, -40)), 2);
				g.line(bc, bc.add(Coord.sc(a + Math.PI / 4, -10)), 2);
				g.line(bc, bc.add(Coord.sc(a - Math.PI / 4, -10)), 2);
				g.chcolor(Color.WHITE);
			}
		}
	}

	private void checkplmove() {
		Gob pl;
		long now = System.currentTimeMillis();
		if ((playergob >= 0) && ((pl = glob.oc.getgob(playergob)) != null)
				&& (pl.sc != null)) {
			Coord plp = pl.position();
			if ((plfpos == null) || !plfpos.equals(plp)) {
				lastmove = now;
				plfpos = plp;
				if ((obscpart != null)
						&& !obscpart.checkhit(pl.sc.add(obscgob.sc.inv()))) {
					obscpart = null;
					obscgob = null;
				}
			} else if (now - lastmove > 500) {
				for (Sprite.Part p : clickable) {
					Gob gob = (Gob) p.owner;
					if ((gob == null) || (gob.sc == null))
						continue;
					if (gob == pl)
						break;
					if (p.checkhit(pl.sc.add(gob.sc.inv()))) {
						obscpart = p;
						obscgob = gob;
						break;
					}
				}
			}
		}
		player_moving = ((now - lastmove) < 400);
	}

	private void checkmappos() {
		if (cam == null)
			return;
		Coord sz = this.sz;
		SlenHud slen = ui.slenhud;
		if (slen != null)
			sz = sz.add(0, -slen.foldheight());
		Gob player = glob.oc.getgob(playergob);
		if (player != null)
			cam.setpos(this, player, sz);
	}
	
	//Kerri	
	Coord lastWASD = new Coord(0, 0);
	public void update(long dt)
	{
		if (Config.use_wasd) {
			Coord newWASD = APXUtils.updateWASD();
			if (!newWASD.equals(lastWASD)) {
				lastWASD = newWASD;
				map_click_ntf(lastWASD.x, lastWASD.y, 1, 0);
			}
		}
		
		Gob pl = glob.oc.getgob(playergob);
		Coord myCurrentCoord = null;
		if(pl != null)
		{
			myCurrentCoord = pl.position();
			if(myCurrentCoord != null && myLastCoord != null)
				if(myCurrentCoord.dist(myLastCoord) > 30*11 && cam != null) {
					cam.reset();
				}
		}
		myLastCoord = myCurrentCoord;
		
		update_pf_moving();
	}
	
	//Kerri
	private void drawTileSelection(GOut g, Coord tc, Coord sc) {
		Coord c1 = sc;
		Coord c2 = sc.add(m2s(new Coord(0, tileSize.y)));
		Coord c3 = sc.add(m2s(new Coord(tileSize.x, tileSize.y)));
		Coord c4 = sc.add(m2s(new Coord(tileSize.x, 0)));
		Color cl = Color.red;
		g.chcolor(new Color(cl.getRed(), cl.getGreen(), cl.getBlue(), 32));
		g.frect(c1, c2, c3, c4);
		g.chcolor(cl);
		g.line(c2, c1, 2);
		g.line(c1.add(1, 0), c4.add(1, 0), 2);
		g.line(c4.add(1, 0), c3.add(1, 0), 2);
		g.line(c3, c2, 2);
		g.chcolor();
	}
	
	private void drawJSRect(GOut g, Coord sc, Coord size) {
		Coord c1 = sc;
		Coord c2 = sc.add(m2s(new Coord(0, tileSize.y * size.y)));
		Coord c3 = sc.add(m2s(new Coord(tileSize.x * size.x, tileSize.y * size.y)));
		Coord c4 = sc.add(m2s(new Coord(tileSize.x * size.x, 0)));
		Color cl = Color.cyan;
		g.chcolor(new Color(cl.getRed(), cl.getGreen(), cl.getBlue(), 32));
		g.frect(c1, c2, c3, c4);
		g.chcolor(cl);
		g.line(c2, c1, 2);
		g.line(c1.add(1, 0), c4.add(1, 0), 2);
		g.line(c4.add(1, 0), c3.add(1, 0), 2);
		g.line(c3, c2, 2);
		g.chcolor();
	}
	
	public void drawQuad(GOut g, Coord sc, Color c) {
		Coord c1 = sc;
		Coord c2 = sc.add(m2s(new Coord(0, tileSize.y)));
		Coord c3 = sc.add(m2s(new Coord(tileSize.x, tileSize.y)));
		Coord c4 = sc.add(m2s(new Coord(tileSize.x, 0)));
		g.chcolor(c);
		g.frect(c1, c2, c3, c4);
		g.chcolor();
	}

	public void draw(GOut og) {
		if(!Config.render_enable)
		{
			Coord requl = mc.add(-500, -500).div(tileSize).div(cmaps);
			Coord reqbr = mc.add(500, 500).div(tileSize).div(cmaps);
			Coord cgc = new Coord(0, 0);
			for (cgc.y = requl.y; cgc.y <= reqbr.y; cgc.y++) {
				for (cgc.x = requl.x; cgc.x <= reqbr.x; cgc.x++) {
					if (map.grids.get(cgc) == null)
						map.request(new Coord(cgc));
				}
			}
			map.sendreqs();
			checkplmove();
			return;
		}
		if (moveto != null) {
			wdgmsg("click", moveto, moveto, 1, 0);
			moveto = null;
		}
		hsz = MainFrame.getInnerSize();
		sz = hsz.mul(1 / getScale());
		GOut g = og.reclip(Coord.z, sz);
		g.gl.glPushMatrix();
		g.scale(getScale());
		checkmappos();
		Coord requl = mc.add(-500, -500).div(tileSize).div(cmaps);
		Coord reqbr = mc.add(500, 500).div(tileSize).div(cmaps);
		Coord cgc = new Coord(0, 0);
		for (cgc.y = requl.y; cgc.y <= reqbr.y; cgc.y++) {
			for (cgc.x = requl.x; cgc.x <= reqbr.x; cgc.x++) {
				if (map.grids.get(cgc) == null)
					map.request(new Coord(cgc));
			}
		}
		long now = System.currentTimeMillis();
		if ((olftimer != 0) && (olftimer < now))
			unflashol();
		map.sendreqs();
		checkplmove();
		// try {
		if (((mask.amb = glob.amblight) == null) || Config.nightvision)
			mask.amb = new Color(0, 0, 0, 0);
		drawmap(g);
		
		// movement highlight
		try {
			if (Config.showpath) {
				Coord oc = viewoffset(sz, mc);
				Coord pc, cc;
				//g.chcolor(Color.GREEN);
				synchronized (glob.oc) {
					for (Gob gob : glob.oc) {
						if(gob == null) continue;
						if(gob.sc == null) continue;
						if (!(gob.isPlayer() || gob.resname().contains("boat")) && !Config.showpathAll) continue;
						Moving move_attr = gob.getattr(Moving.class);
						if(move_attr == null) continue;
						if (move_attr instanceof LinMove) {
							LinMove lin_move = (LinMove) move_attr;
							pc = m2s(lin_move.t).add(oc);
							if(gob.id == playergob)
						    	g.chcolor(Color.GREEN);
						    else
						    	g.chcolor(Color.orange);
							g.line(gob.sc, pc, 2);
							if (gob.id == playergob) {
								for(Coord c:glob.oc.movequeue){
								    cc = m2s(c).add(oc);
								    g.line(pc, cc, 2);
								    pc = cc;
								}
							}
						}
					}
				}
				g.chcolor();
				//Gob player = glob.oc.getgob(playergob);
				/*if (player != null) {
					Moving m = player.getattr(Moving.class);
					g.chcolor(Color.GREEN);
					if ((m != null) && (m instanceof LinMove)) {
						LinMove lm = (LinMove) m;
						pc = m2s(lm.t).add(oc);
						g.line(player.sc, pc, 2);
						for (Coord c : glob.oc.movequeue) {
							cc = m2s(c).add(oc);
							g.line(pc, cc, 2);
							pc = cc;
						}
					}
					g.chcolor();
				}*/
			}
		} catch (Exception ex) {
			
		}
		// ###############
		// PF 
		if (path != null && path.size() > 1) {
			Coord oc = viewoffset(sz, mc);
			g.chcolor(Color.green);
			for (int i = 0; i < path.size() - 1; i++) {
				g.line(m2s(path.get(i)).add(oc), m2s(path.get(i + 1)).add(oc), 2);
			}
			g.chcolor();
		}
		drawarrows(g);
		g.chcolor(Color.WHITE);

		// } catch(Loading l) {
		// String text = "Loading...";
		// g.chcolor(Color.BLACK);
		// g.frect(Coord.z, sz);
		// g.chcolor(Color.WHITE);
		// g.atext(text, sz, 0.5, 0.5);
		// }
		long poldt = now - polchtm;
		if ((polownert != null) && (poldt < 6000)) {
			int a;
			if (poldt < 1000)
				a = (int) ((255 * poldt) / 1000);
			else if (poldt < 4000)
				a = 255;
			else
				a = (int) ((255 * (2000 - (poldt - 4000))) / 2000);
			g.chcolor(255, 255, 255, a);
			g.aimage(polownert.tex(), sz.div(2), 0.5, 0.5);
			g.chcolor();
		}
		g.gl.glPopMatrix();
		//Kerri. debug
		if (Config.showDebug) {
			int ay = 120;
			int margin = 15;
			g.atext("FPS: " + MainFrame.havenPanel.fps, new Coord(10, ay), 0, 1);
			ay = ay + margin;
			if (objectUnderMouse != null) {
				g.atext("Object id under mouse: " + objectUnderMouse.id + " Coords: "
						+ objectUnderMouse.position(), new Coord(10, ay), 0, 1);
				ay = ay + margin;
				g.atext("Resource name: "+objectUnderMouse.resname()+
						" BLOB: "+objectUnderMouse.GetBlob(0), new Coord(10, ay), 0, 1);
				ay = ay + margin;
			} else {
				g.atext("Object id under mouse: NULL", new Coord(10, ay), 0, 1);
				ay = ay + margin;
			}
			if (mousepos != null) {
				g.atext("Mouse map pos: " + mousepos.toString() + " Tile: " + getTileFix(mousepos.div(tileSize))  + "TilifNS: " + tilefy_ns(mousepos).toString(), new Coord(10, ay), 0, 1);
				ay = ay + margin;
				g.atext("Tile coord: " + mouseAtTile.toString(), new Coord(10, ay), 0, 1);
				ay = ay + margin;
			}
			g.atext("Current cursor: " + UI.instance.root.cursor.name.replace("gfx/hud/curs/", ""),
					new Coord(10, ay), 0, 1);
			ay = ay + margin;
			g.atext("Player id: " + playergob, new Coord(10, ay), 0, 1);
		}//debug
		if (Config.dbtext)
			g.atext(mc.toString(), new Coord(10, 560), 0, 1);
		super.draw(og);
	}

	public boolean drop(Coord cc, Coord ul) {
		wdgmsg("drop", ui.modflags());
		return (true);
	}

	public boolean iteminteract(Coord cc, Coord ul) {
		Coord cc0 = cc;
		cc = new Coord((int) (cc.x / getScale()), (int) (cc.y / getScale()));
		Gob hit = gobatpos(cc);
		Coord mc = s2m(cc.add(viewoffset(sz, this.mc).inv()));
		if (Config.assign_to_tile) mc = tilify(mc);
		if (hit == null)
			wdgmsg("itemact", cc0, mc, ui.modflags());
		else
			wdgmsg("itemact", cc0, mc, ui.modflags(), hit.id, hit.position());
		return (true);
	}

	private Map<String, Console.Command> cmdmap = new TreeMap<String, Console.Command>();
	{
		cmdmap.put("cam", new Console.Command() {
			public void run(Console cons, String[] args) {
				if (args.length >= 2) {
					Class<? extends Camera> ct = camtypes.get(args[1]);
					String[] cargs = new String[args.length - 2];
					System.arraycopy(args, 2, cargs, 0, cargs.length);
					if (ct != null) {
						try {
							MapView.this.cam = makecam(ct, cargs);
							Utils.setpref("defcam", args[1]);
							Utils.setprefb("camargs", Utils.serialize(cargs));
						} catch (ClassNotFoundException e) {
							throw (new RuntimeException("no such camera: "
									+ args[1]));
						}
					} else {
						throw (new RuntimeException("no such camera: "
								+ args[1]));
					}
				}
			}
		});
		cmdmap.put("plol", new Console.Command() {
			public void run(Console cons, String[] args) {
				Indir<Resource> res = Resource.load(args[1]).indir();
				Message sdt;
				if (args.length > 2)
					sdt = new Message(0, Utils.hex2byte(args[2]));
				else
					sdt = new Message(0);
				Gob pl;
				if ((playergob >= 0)
						&& ((pl = glob.oc.getgob(playergob)) != null))
					pl.ols.add(new Gob.Overlay(-1, res, sdt));
			}
		});
	}

	public Map<String, Console.Command> findcmds() {
		return (cmdmap);
	}
	
	ArrayList<Coord> path;
	int path_step = 0;
	boolean path_moving = false;
	Gob path_interact_object = null;
	boolean draw_pf_map = false;
	
	public void toggle_draw_pf() {
		if (!draw_pf_map) {
			draw_pf_map = true;
			APXUtils._pf_compute(0);
		} else {
			draw_pf_map = false;
		}
	}
	
	public int map_pf_move(Coord real_coord) {
		if (path != null) {
			path.clear();
			path_moving = false;
			path_step = 0;
			path_interact_object = null;
		}
		path = APXUtils._pf_find_path(real_coord, 0);
		update_pf_moving();
		return path == null ? -1 : path.size();
	}
	
	public int map_pf_interact(int id) {
		if (path != null) {
			path.clear();
			path_moving = false;
			path_step = 0;
			path_interact_object = null;
		}
		Gob pgob;
		synchronized (glob.oc) {
			pgob = glob.oc.getgob(id);
		}
		if (pgob == null)
			return -1;
		path_interact_object = pgob;
		path = APXUtils._pf_find_path(pgob.position(), id);
		update_pf_moving();
		return path == null ? -1 : path.size();
	}
	
	public void update_pf_moving() {
		if (path == null)
			return;
		if (JSBotUtils.isMoving()) return;
		
		if (path_step < path.size()) {
			if (myLastCoord.equals(path.get(path_step))) {
				path_moving = false;
				path_step++;
			}
		}
		if (path_moving) return;
		if (path_step < path.size()) {
			if (path.size() - path_step == 1 && path_interact_object != null) {
				//click, (261, 284), (-4062515, 1117484), 3, 0, -1725142871, (-4062515, 1117495)
				wdgmsg("click", JSBotUtils.getCenterScreenCoord(), path_interact_object.position(), 3, 0, path_interact_object.id, path_interact_object.position());
				path_step++;
			} else {
				path_moving = true;
				Coord togo = path.get(path_step);
				wdgmsg("click", JSBotUtils.getCenterScreenCoord(), tilify(togo), 1, 0);
			}
		} else {
			path = null;
			path_step = 0;
			path_moving = false;
		}
	}