/**
* Copyright (c) Lambda Innovation, 2013-2016
* This file is part of the AcademyCraft mod.
* https://github.com/LambdaInnovation/AcademyCraft
* Licensed under GPLv3, see project root for more information.
*/
package cn.academy.ability.develop;
import cn.academy.ability.develop.action.IDevelopAction;
import cn.lambdalib.annoreg.core.Registrant;
import cn.lambdalib.s11n.SerializeDynamic;
import cn.lambdalib.s11n.SerializeIncluded;
import cn.lambdalib.s11n.SerializeNullable;
import cn.lambdalib.util.datapart.DataPart;
import cn.lambdalib.util.datapart.EntityData;
import cn.lambdalib.util.datapart.RegDataPart;
import cpw.mods.fml.relauncher.Side;
import net.minecraft.entity.player.EntityPlayer;
@Registrant
@RegDataPart(EntityPlayer.class)
public class DevelopData extends DataPart<EntityPlayer> {
public static DevelopData get(EntityPlayer player) {
return EntityData.get(player).getPart(DevelopData.class);
}
public enum DevState { IDLE, FAILED, DEVELOPING, DONE }
private boolean dirty = false;
@SerializeIncluded
@SerializeDynamic
@SerializeNullable
private IDeveloper developer;
private IDevelopAction type;
@SerializeIncluded
private int stim;
@SerializeIncluded
private int maxStim;
@SerializeIncluded
private DevState state = DevState.IDLE;
private int tickThisStim;
private int tickSync;
public DevelopData() {
setTick(true);
}
// API
/**
* Make the player start developing with given Developer and Type.
* If currently is developing the previous action will be overridden.
*/
public void startDeveloping(IDeveloper _developer, IDevelopAction _type) {
checkSide(Side.SERVER);
resetProgress(false);
developer = _developer;
type = _type;
state = DevState.DEVELOPING;
maxStim = type.getStimulations(getEntity());
dirty = true;
}
/**
* @return Whether the player is developing ability.
*/
public boolean isDeveloping() {
return developer != null;
}
/**
* @return The develop progress [0, 1], 0.0 if not developing
*/
public double getDevelopProgress() {
if (isDeveloping()) {
return (double) stim / maxStim + (double) tickThisStim / developer.getType().getTPS();
} else {
return 0;
}
}
/**
* @return Current developer type or null if not developing
*/
public IDevelopAction getDevelopType() {
return type;
}
public int getStim() {
return stim;
}
public DevState getState() {
return state;
}
public int getMaxStim() {
return maxStim;
}
public void abort() {
checkSide(Side.SERVER);
if(state == DevState.DEVELOPING) {
resetProgress(true);
}
}
public void reset() {
// checkSide(Side.SERVER);
resetProgress(false);
}
// Internal
private void resetProgress(boolean failed) {
developer = null;
type = null;
tickSync = 5;
stim = maxStim = tickThisStim = 0;
state = failed ? DevState.FAILED : DevState.IDLE;
dirty = true;
}
@Override
public void tick() {
if(!isClient()) {
EntityPlayer player = getEntity();
if(dirty) {
dirty = false;
sync();
}
if(isDeveloping()) {
DeveloperType devType = developer.getType();
// Sync
if(tickSync-- == 0) {
tickSync = 5;
sync();
}
// Logic
double consume = devType.getCPS() / devType.getTPS();
if(!developer.tryPullEnergy(consume)) {
resetProgress(true);
return;
}
if(++tickThisStim > devType.getTPS()) {
tickThisStim = 0;
++stim;
if(stim >= maxStim) {
// try perform the action.
boolean success = type.validate(player, developer);
if(success) {
type.onLearned(player);
}
resetProgress(!success);
if (success) {
state = DevState.DONE;
}
}
}
}
}
}
}