/*
* Copyright 2016 Nathan Howard
*
* This file is part of OpenGrave
*
* OpenGrave is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenGrave 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.
*
* You should have received a copy of the GNU General Public License
* along with OpenGrave. If not, see <http://www.gnu.org/licenses/>.
*/
package com.opengrave.og.engine;
import java.io.IOException;
import java.util.ArrayList;
import java.util.UUID;
import com.opengrave.common.DebugExceptionHandler;
import com.opengrave.common.MenuInfo;
import com.opengrave.common.OGOutputStream;
import com.opengrave.common.PopupMenuOption;
import com.opengrave.common.pathing.Path;
import com.opengrave.common.pathing.Point;
import com.opengrave.common.world.CommonLocation;
import com.opengrave.common.world.CommonObject;
import com.opengrave.common.world.CommonObject.Type;
import com.opengrave.common.world.MaterialList;
import com.opengrave.og.Util;
import com.opengrave.og.base.Pickable;
import com.opengrave.og.base.Renderable3D;
import com.opengrave.og.resources.RenderStyle;
import com.opengrave.og.util.Matrix4f;
import com.opengrave.og.util.Vector3f;
public abstract class BaseObject extends Node implements Pickable {
private String identifier = "unknown";
public Renderable3D renderable;
protected MaterialList matList;
private String modelLabel;
public Location location;
public RenderStyle style;
protected CommonObject cobj;
private Path path;
protected float timeSinceTick = 0f;
protected double lastTick, nextTick;
protected Surface s;
protected Point lookPoint;
protected BaseObject lookObj;
protected boolean visible = true;
public boolean drawOutline = true;
public void moveBasedOnPath(float delta) {
if (path == null) {
this.stopAnimation("walk");
return;
}
timeSinceTick += delta;
double time = timeSinceTick;
if (time > 250f) { // 250ms, once tick len
// this.stopAnimation("walk"); // We've gone as far as we can this
// tick, server may be running too slow. Don't walk-anim on the
// spot.
time = 250f;
} else {
this.startAnimation("walk", 0.3f / 1000f, false);
}
time = time / 250.0;
double dist = lastTick + ((nextTick - lastTick) * time);
CommonLocation cl = path.getLocation(dist);
location.setFullX(cl.getFullXAsFloat());
location.setFullY(cl.getFullYAsFloat());
location.setLayer(cl.getLayer());
}
public void tick(double lastTick, double nextTick) {
timeSinceTick = 0f;
this.lastTick = lastTick;
this.nextTick = nextTick;
}
public void setSurface(Surface s) {
this.s = s;
}
public BaseObject(CommonObject cobj) {
this.cobj = cobj;
identifier = cobj.getIdentifier();
matList = cobj.getMaterialList();
modelLabel = cobj.getModelLabel();
location = new Location(cobj.getLocation());
renderableLabelChanged(modelLabel);
}
public abstract String getType();
public void save(OGOutputStream stream) {
try {
stream.writeString(getType());
stream.writeString(modelLabel);
stream.writeLocation(location);
stream.writeMaterialList(matList);
} catch (IOException e) {
new DebugExceptionHandler(e);
}
}
public String getModelLabel() {
return modelLabel;
}
public float getX() {
return location.getFullXAsFloat();
}
public float getY() {
return location.getFullYAsFloat();
}
public float getZ() {
return location.getZ();
}
public Vector3f getAngles() {
return location.getRotate();
}
public void setMaterialList(MaterialList matList) {
this.matList = matList;
}
public String getRenderableLabel() {
return modelLabel;
}
public void setRenderableLabel(String s) {
renderableLabelChanged(s);
modelLabel = s;
}
public BaseObject setLocation(CommonLocation l) {
location = new Location(l);
return this;
}
public Location getLocation() {
return location;
}
public BaseObject setRenderable(String s) {
cobj.setModelLabel(s);
setRenderableLabel(s);
// renderable = Resources.getStaticModel(s).getRenderable();
return this;
}
public abstract void renderableLabelChanged(String s);
public void setX(float number) {
location.setFullX(number);
}
public void setY(float number) {
location.setFullY(number);
}
public void setZ(float number) {
location.setZ(number);
}
public void setAngle(Vector3f vector3f) {
// location.getRotate().z = number;
// Vector3f r = location.getRotate();
location.setRotate(vector3f.x, vector3f.y, vector3f.z);
}
public void setRenderStyle(RenderStyle style) {
this.style = style;
}
public abstract void startAnimation(String name, float speed, boolean once);
public abstract void stopAnimation(String name);
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String string) {
identifier = string;
}
public RenderView getContext() {
return context;
}
@Override
public Matrix4f getMatrix() {
return Util.createMatrixFor(location, null, null, null);
}
public BaseObject clone() {
return createObject(cobj);
}
public abstract BoundingBox getBoundingBox();
public String getRenderableFile() {
int pos = modelLabel.indexOf(":");
return modelLabel.substring(0, pos);
}
public String getRenderableSection(int i) {
String[] split = modelLabel.split(":");
if (i + 1 >= split.length) {
return "";
}
return split[i + 1];
}
public MaterialList getMaterialList() {
return matList;
}
public int getRenderableSectionCount() {
String[] split = modelLabel.split(":");
return split.length - 1;
}
public void setRenderableSection(int number, String text) {
String[] split = modelLabel.split(":", -1); // -1 keeps empty trailing
// elements, which is
// correct here
String newS = split[0];
int last = split.length;
if (number + 1 >= last) {
last = number + 2;
} // These numbers looks so wrong, but it works so meh
for (int i = 1; i < last; i++) {
if (number == i - 1) {
newS += ":" + text;
} else {
if (i < last) {
newS += ":" + split[i];
} else {
newS += ":";
}
}
}
setRenderable(newS);
}
public void setRenderableFile(String fileName) {
int i = modelLabel.indexOf(":");
if (i == -1) {
setRenderable(fileName);
return;
}
String end = modelLabel.substring(modelLabel.indexOf(":"));
setRenderable(fileName + end);
}
public static BaseObject createObject(CommonObject cobj) {
if (cobj == null) {
return null;
}
Type cT = cobj.getType();
if (cT == Type.Static) {
return new StaticObject(cobj);
} else if (cT == Type.Anim) {
AnimatedObject a = new AnimatedObject(cobj);
// TODO Smarter setup of gaits and walk systems
// if(cobj.getModelLabel().startsWith("mod/craig.dae")){
// a.setWalk(new BipedWalk(a,
// a.getSkeleton().getBone("UpperLeg.left"),
// a.getSkeleton().getBone("UpperLeg.right")));
// }
return a;
} else if (cT == Type.Particle) {
return new ParticleObject(cobj);
}
return null;
}
public CommonObject getCommonObject() {
return cobj;
}
public UUID getUUID() {
return cobj.getUUID();
}
public void setPath(Path path) {
this.path = path;
}
public Path getPath() {
return path;
}
public void lookAt(Point point) {
lookObj = null;
lookPoint = point;
}
public void lookAt() {
Point point = lookPoint;
if (lookPoint == null) {
if (lookObj == null) {
return;
}
point = new Point(lookObj.getLocation());
}
Point here = new Point(getLocation());
if (point.getDistance(here) < 0.1) {
return;
}
double angle = Math.toDegrees(here.getAngle(point)) - 270;
getLocation().setAngleZ((float) angle);
}
public void setVisible(boolean checked) {
visible = checked;
}
public void moveTo(CommonLocation l) {
setLocation(l);
}
public void lookDir(Point point) {
lookPoint = null;
lookObj = null;
Point here = new Point(getLocation());
Point inc = new Point(here);
inc.add(point);
if (here.getDistance(inc) < 0.1) {
return;
}
double angle = Math.toDegrees(here.getAngle(inc)) - 90;
getLocation().setAngleZ((float) angle);
}
public ArrayList<PopupMenuOption> createMenuList(String context, int page) {
// TODO Populate popup menu from actions available on server. Best to
// send with the CommonObject over net
ArrayList<PopupMenuOption> list = new ArrayList<PopupMenuOption>();
list.add(new PopupMenuOption("cancel", "tex/guicross.png", "Cancel"));
if (context.equals("none")) {
// No context
list.add(new PopupMenuOption("menu:interact:0", "tex/guiinteract.png", "Interact"));
list.add(new PopupMenuOption("menu:combat:0", "tex/guicombat.png", "Combat"));
list.add(new PopupMenuOption("menu:spell:0", "tex/guispell.png", "Spell"));
} else if (context.equals("interact")) {
list.add(new PopupMenuOption("talk", "tex/guitalk.png", "Talk"));
list.add(new PopupMenuOption("pickpocket", "tex/guipickpocket.png", "Pickpocket"));
list.add(new PopupMenuOption("trade", "tex/guitrade.png", "Trade"));
} else if (context.equals("combat")) {
list.add(new PopupMenuOption("kill", "tex/guikill.png", "Kill"));
list.add(new PopupMenuOption("subdue", "tex/guisubdue.png", "Subdue"));
list.add(new PopupMenuOption("kidnap", "tex/guikidnap.png", "Kidnap"));
} else if (context.equals("spell")) {
list.add(new PopupMenuOption("influence", "tex/guiinfluence.png", "Influence"));
list.add(new PopupMenuOption("confuse", "tex/guiconfuse.png", "Confuse"));
list.add(new PopupMenuOption("heal", "tex/guiheal.png", "Heal"));
}
return list;
}
public RenderStyle getRenderStyle() {
return style;
}
public MenuInfo getMenuInfo() {
return cobj.getMenuInfo();
}
}