Initial commit
This commit is contained in:
commit
b0e73a61aa
16345 files changed
+3104967
No files matched your search
@@ -0,0 +1,342 @@
|
||||
//package net.minecraft.world.phys;
|
||||
|
||||
//import java->util.ArrayList;
|
||||
//import java->util.List;
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "AABB.h"
|
||||
#include "HitResult.h"
|
||||
|
||||
DWORD AABB::tlsIdx = 0;
|
||||
AABB::ThreadStorage *AABB::tlsDefault = NULL;
|
||||
|
||||
AABB::ThreadStorage::ThreadStorage()
|
||||
{
|
||||
pool = new AABB[POOL_SIZE];
|
||||
poolPointer = 0;
|
||||
}
|
||||
|
||||
|
||||
AABB::ThreadStorage::~ThreadStorage()
|
||||
{
|
||||
delete pool;
|
||||
}
|
||||
|
||||
void AABB::CreateNewThreadStorage()
|
||||
{
|
||||
ThreadStorage *tls = new ThreadStorage();
|
||||
if(tlsDefault == NULL )
|
||||
{
|
||||
tlsIdx = TlsAlloc();
|
||||
tlsDefault = tls;
|
||||
}
|
||||
|
||||
TlsSetValue(tlsIdx, tls);
|
||||
}
|
||||
|
||||
void AABB::UseDefaultThreadStorage()
|
||||
{
|
||||
TlsSetValue(tlsIdx, tlsDefault);
|
||||
}
|
||||
|
||||
void AABB::ReleaseThreadStorage()
|
||||
{
|
||||
ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx);
|
||||
if( tls == tlsDefault ) return;
|
||||
|
||||
delete tls;
|
||||
}
|
||||
|
||||
AABB *AABB::newPermanent(double x0, double y0, double z0, double x1, double y1, double z1)
|
||||
{
|
||||
return new AABB(x0, y0, z0, x1, y1, z1);
|
||||
}
|
||||
|
||||
void AABB::clearPool()
|
||||
{
|
||||
}
|
||||
|
||||
void AABB::resetPool()
|
||||
{
|
||||
}
|
||||
|
||||
AABB *AABB::newTemp(double x0, double y0, double z0, double x1, double y1, double z1)
|
||||
{
|
||||
ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx);
|
||||
AABB *thisAABB = &tls->pool[tls->poolPointer];
|
||||
thisAABB->set(x0, y0, z0, x1, y1, z1);
|
||||
tls->poolPointer = ( tls->poolPointer + 1 ) % ThreadStorage::POOL_SIZE;
|
||||
return thisAABB;
|
||||
}
|
||||
|
||||
AABB::AABB(double x0, double y0, double z0, double x1, double y1, double z1)
|
||||
{
|
||||
this->x0 = x0;
|
||||
this->y0 = y0;
|
||||
this->z0 = z0;
|
||||
this->x1 = x1;
|
||||
this->y1 = y1;
|
||||
this->z1 = z1;
|
||||
}
|
||||
|
||||
|
||||
AABB *AABB::set(double x0, double y0, double z0, double x1, double y1, double z1)
|
||||
{
|
||||
this->x0 = x0;
|
||||
this->y0 = y0;
|
||||
this->z0 = z0;
|
||||
this->x1 = x1;
|
||||
this->y1 = y1;
|
||||
this->z1 = z1;
|
||||
return this;
|
||||
}
|
||||
|
||||
AABB *AABB::expand(double xa, double ya, double za)
|
||||
{
|
||||
double _x0 = x0;
|
||||
double _y0 = y0;
|
||||
double _z0 = z0;
|
||||
double _x1 = x1;
|
||||
double _y1 = y1;
|
||||
double _z1 = z1;
|
||||
|
||||
if (xa < 0) _x0 += xa;
|
||||
if (xa > 0) _x1 += xa;
|
||||
|
||||
if (ya < 0) _y0 += ya;
|
||||
if (ya > 0) _y1 += ya;
|
||||
|
||||
if (za < 0) _z0 += za;
|
||||
if (za > 0) _z1 += za;
|
||||
|
||||
return AABB::newTemp(_x0, _y0, _z0, _x1, _y1, _z1);
|
||||
}
|
||||
|
||||
AABB *AABB::grow(double xa, double ya, double za)
|
||||
{
|
||||
double _x0 = x0 - xa;
|
||||
double _y0 = y0 - ya;
|
||||
double _z0 = z0 - za;
|
||||
double _x1 = x1 + xa;
|
||||
double _y1 = y1 + ya;
|
||||
double _z1 = z1 + za;
|
||||
|
||||
return AABB::newTemp(_x0, _y0, _z0, _x1, _y1, _z1);
|
||||
}
|
||||
|
||||
AABB *AABB::cloneMove(double xa, double ya, double za)
|
||||
{
|
||||
return AABB::newTemp(x0 + xa, y0 + ya, z0 + za, x1 + xa, y1 + ya, z1 + za);
|
||||
}
|
||||
|
||||
double AABB::clipXCollide(AABB *c, double xa)
|
||||
{
|
||||
if (c->y1 <= y0 || c->y0 >= y1) return xa;
|
||||
if (c->z1 <= z0 || c->z0 >= z1) return xa;
|
||||
|
||||
if (xa > 0 && c->x1 <= x0)
|
||||
{
|
||||
double max = x0 - c->x1;
|
||||
if (max < xa) xa = max;
|
||||
}
|
||||
if (xa < 0 && c->x0 >= x1)
|
||||
{
|
||||
double max = x1 - c->x0;
|
||||
if (max > xa) xa = max;
|
||||
}
|
||||
|
||||
return xa;
|
||||
}
|
||||
|
||||
double AABB::clipYCollide(AABB *c, double ya)
|
||||
{
|
||||
if (c->x1 <= x0 || c->x0 >= x1) return ya;
|
||||
if (c->z1 <= z0 || c->z0 >= z1) return ya;
|
||||
|
||||
if (ya > 0 && c->y1 <= y0)
|
||||
{
|
||||
double max = y0 - c->y1;
|
||||
if (max < ya) ya = max;
|
||||
}
|
||||
if (ya < 0 && c->y0 >= y1)
|
||||
{
|
||||
double max = y1 - c->y0;
|
||||
if (max > ya) ya = max;
|
||||
}
|
||||
|
||||
return ya;
|
||||
}
|
||||
|
||||
double AABB::clipZCollide(AABB *c, double za)
|
||||
{
|
||||
if (c->x1 <= x0 || c->x0 >= x1) return za;
|
||||
if (c->y1 <= y0 || c->y0 >= y1) return za;
|
||||
|
||||
if (za > 0 && c->z1 <= z0)
|
||||
{
|
||||
double max = z0 - c->z1;
|
||||
if (max < za) za = max;
|
||||
}
|
||||
if (za < 0 && c->z0 >= z1)
|
||||
{
|
||||
double max = z1 - c->z0;
|
||||
if (max > za) za = max;
|
||||
}
|
||||
|
||||
return za;
|
||||
}
|
||||
|
||||
bool AABB::intersects(AABB *c)
|
||||
{
|
||||
if (c->x1 <= x0 || c->x0 >= x1) return false;
|
||||
if (c->y1 <= y0 || c->y0 >= y1) return false;
|
||||
if (c->z1 <= z0 || c->z0 >= z1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AABB::intersectsInner(AABB *c)
|
||||
{
|
||||
if (c->x1 < x0 || c->x0 > x1) return false;
|
||||
if (c->y1 < y0 || c->y0 > y1) return false;
|
||||
if (c->z1 < z0 || c->z0 > z1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
AABB *AABB::move(double xa, double ya, double za)
|
||||
{
|
||||
x0 += xa;
|
||||
y0 += ya;
|
||||
z0 += za;
|
||||
x1 += xa;
|
||||
y1 += ya;
|
||||
z1 += za;
|
||||
return this;
|
||||
}
|
||||
|
||||
bool AABB::intersects(double x02, double y02, double z02, double x12, double y12, double z12)
|
||||
{
|
||||
if (x12 <= x0 || x02 >= x1) return false;
|
||||
if (y12 <= y0 || y02 >= y1) return false;
|
||||
if (z12 <= z0 || z02 >= z1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AABB::contains(Vec3 *p)
|
||||
{
|
||||
if (p->x <= x0 || p->x >= x1) return false;
|
||||
if (p->y <= y0 || p->y >= y1) return false;
|
||||
if (p->z <= z0 || p->z >= z1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 4J Added
|
||||
bool AABB::containsIncludingLowerBound(Vec3 *p)
|
||||
{
|
||||
if (p->x < x0 || p->x >= x1) return false;
|
||||
if (p->y < y0 || p->y >= y1) return false;
|
||||
if (p->z < z0 || p->z >= z1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
double AABB::getSize()
|
||||
{
|
||||
double xs = x1 - x0;
|
||||
double ys = y1 - y0;
|
||||
double zs = z1 - z0;
|
||||
return (xs + ys + zs) / 3.0f;
|
||||
}
|
||||
|
||||
AABB *AABB::shrink(double xa, double ya, double za)
|
||||
{
|
||||
double _x0 = x0 + xa;
|
||||
double _y0 = y0 + ya;
|
||||
double _z0 = z0 + za;
|
||||
double _x1 = x1 - xa;
|
||||
double _y1 = y1 - ya;
|
||||
double _z1 = z1 - za;
|
||||
|
||||
return AABB::newTemp(_x0, _y0, _z0, _x1, _y1, _z1);
|
||||
}
|
||||
|
||||
AABB *AABB::copy()
|
||||
{
|
||||
return AABB::newTemp(x0, y0, z0, x1, y1, z1);
|
||||
}
|
||||
|
||||
HitResult *AABB::clip(Vec3 *a, Vec3 *b)
|
||||
{
|
||||
Vec3 *xh0 = a->clipX(b, x0);
|
||||
Vec3 *xh1 = a->clipX(b, x1);
|
||||
|
||||
Vec3 *yh0 = a->clipY(b, y0);
|
||||
Vec3 *yh1 = a->clipY(b, y1);
|
||||
|
||||
Vec3 *zh0 = a->clipZ(b, z0);
|
||||
Vec3 *zh1 = a->clipZ(b, z1);
|
||||
|
||||
if (!containsX(xh0)) xh0 = NULL;
|
||||
if (!containsX(xh1)) xh1 = NULL;
|
||||
if (!containsY(yh0)) yh0 = NULL;
|
||||
if (!containsY(yh1)) yh1 = NULL;
|
||||
if (!containsZ(zh0)) zh0 = NULL;
|
||||
if (!containsZ(zh1)) zh1 = NULL;
|
||||
|
||||
Vec3 *closest = NULL;
|
||||
|
||||
if (xh0 != NULL && (closest == NULL || a->distanceToSqr(xh0) < a->distanceToSqr(closest))) closest = xh0;
|
||||
if (xh1 != NULL && (closest == NULL || a->distanceToSqr(xh1) < a->distanceToSqr(closest))) closest = xh1;
|
||||
if (yh0 != NULL && (closest == NULL || a->distanceToSqr(yh0) < a->distanceToSqr(closest))) closest = yh0;
|
||||
if (yh1 != NULL && (closest == NULL || a->distanceToSqr(yh1) < a->distanceToSqr(closest))) closest = yh1;
|
||||
if (zh0 != NULL && (closest == NULL || a->distanceToSqr(zh0) < a->distanceToSqr(closest))) closest = zh0;
|
||||
if (zh1 != NULL && (closest == NULL || a->distanceToSqr(zh1) < a->distanceToSqr(closest))) closest = zh1;
|
||||
|
||||
if (closest == NULL) return NULL;
|
||||
|
||||
int face = -1;
|
||||
|
||||
if (closest == xh0) face = 4;
|
||||
if (closest == xh1) face = 5;
|
||||
if (closest == yh0) face = 0;
|
||||
if (closest == yh1) face = 1;
|
||||
if (closest == zh0) face = 2;
|
||||
if (closest == zh1) face = 3;
|
||||
|
||||
return new HitResult(0, 0, 0, face, closest);
|
||||
}
|
||||
|
||||
|
||||
bool AABB::containsX(Vec3 *v)
|
||||
{
|
||||
if (v == NULL) return false;
|
||||
return v->y >= y0 && v->y <= y1 && v->z >= z0 && v->z <= z1;
|
||||
}
|
||||
|
||||
bool AABB::containsY(Vec3 *v)
|
||||
{
|
||||
if (v == NULL) return false;
|
||||
return v->x >= x0 && v->x <= x1 && v->z >= z0 && v->z <= z1;
|
||||
}
|
||||
|
||||
bool AABB::containsZ(Vec3 *v)
|
||||
{
|
||||
if (v == NULL) return false;
|
||||
return v->x >= x0 && v->x <= x1 && v->y >= y0 && v->y <= y1;
|
||||
}
|
||||
|
||||
|
||||
void AABB::set(AABB *b)
|
||||
{
|
||||
this->x0 = b->x0;
|
||||
this->y0 = b->y0;
|
||||
this->z0 = b->z0;
|
||||
this->x1 = b->x1;
|
||||
this->y1 = b->y1;
|
||||
this->z1 = b->z1;
|
||||
}
|
||||
|
||||
wstring AABB::toString()
|
||||
{
|
||||
return L"box[" + _toString<double>(x0) + L", " + _toString<double>(y0) + L", " + _toString<double>(z0) + L" -> " +
|
||||
_toString<double>(x1) + L", " + _toString<double>(y1) + L", " + _toString<double>(z1) + L"]";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "Vec3.h"
|
||||
#include "Definitions.h"
|
||||
|
||||
class HitResult;
|
||||
using namespace std;
|
||||
|
||||
class AABB
|
||||
{
|
||||
// 4J added so we can have separate pools for different threads
|
||||
class ThreadStorage
|
||||
{
|
||||
public:
|
||||
static const int POOL_SIZE = 1024;
|
||||
AABB *pool;
|
||||
unsigned int poolPointer;
|
||||
ThreadStorage();
|
||||
~ThreadStorage();
|
||||
};
|
||||
static DWORD tlsIdx;
|
||||
static ThreadStorage *tlsDefault;
|
||||
public:
|
||||
// Each new thread that needs to use Vec3 pools will need to call one of the following 2 functions, to either create its own
|
||||
// local storage, or share the default storage already allocated by the main thread
|
||||
static void CreateNewThreadStorage();
|
||||
static void UseDefaultThreadStorage();
|
||||
static void ReleaseThreadStorage();
|
||||
|
||||
static AABB *newPermanent(double x0, double y0, double z0, double x1, double y1, double z1);
|
||||
static void clearPool();
|
||||
static void resetPool();
|
||||
static AABB *newTemp(double x0, double y0, double z0, double x1, double y1, double z1);
|
||||
|
||||
double x0, y0, z0;
|
||||
double x1, y1, z1;
|
||||
|
||||
private:
|
||||
AABB(double x0, double y0, double z0, double x1, double y1, double z1);
|
||||
AABB() {}
|
||||
public:
|
||||
AABB *set(double x0, double y0, double z0, double x1, double y1, double z1);
|
||||
AABB *expand(double xa, double ya, double za);
|
||||
AABB *grow(double xa, double ya, double za);
|
||||
public:
|
||||
AABB *cloneMove(double xa, double ya, double za);
|
||||
double clipXCollide(AABB *c, double xa);
|
||||
double clipYCollide(AABB *c, double ya);
|
||||
double clipZCollide(AABB *c, double za);
|
||||
bool intersects(AABB *c);
|
||||
bool intersectsInner(AABB *c);
|
||||
AABB *move(double xa, double ya, double za);
|
||||
bool intersects(double x02, double y02, double z02, double x12, double y12, double z12);
|
||||
bool contains(Vec3 *p);
|
||||
bool containsIncludingLowerBound(Vec3 *p); // 4J Added
|
||||
double getSize();
|
||||
AABB *shrink(double xa, double ya, double za);
|
||||
AABB *copy();
|
||||
HitResult *clip(Vec3 *a, Vec3 *b);
|
||||
bool containsX(Vec3 *v);
|
||||
bool containsY(Vec3 *v);
|
||||
bool containsZ(Vec3 *v);
|
||||
void set(AABB *b);
|
||||
wstring toString();
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
#include "stdafx.h"
|
||||
#include "com.mojang.nbt.h"
|
||||
#include "Abilities.h"
|
||||
|
||||
Abilities::Abilities()
|
||||
{
|
||||
invulnerable = false;
|
||||
flying = false;
|
||||
mayfly = false;
|
||||
instabuild = false;
|
||||
mayBuild = true;
|
||||
flyingSpeed = 0.05f;
|
||||
walkingSpeed = 0.1f;
|
||||
|
||||
#ifdef _DEBUG_MENUS_ENABLED
|
||||
debugflying = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Abilities::addSaveData(CompoundTag *parentTag)
|
||||
{
|
||||
CompoundTag *tag = new CompoundTag();
|
||||
|
||||
tag->putBoolean(L"invulnerable", invulnerable);
|
||||
tag->putBoolean(L"flying", flying);
|
||||
tag->putBoolean(L"mayfly", mayfly);
|
||||
tag->putBoolean(L"instabuild", instabuild);
|
||||
tag->putBoolean(L"mayBuild", mayBuild);
|
||||
tag->putFloat(L"flySpeed", flyingSpeed);
|
||||
tag->putFloat(L"walkSpeed", walkingSpeed);
|
||||
|
||||
parentTag->put(L"abilities", tag);
|
||||
|
||||
}
|
||||
|
||||
void Abilities::loadSaveData(CompoundTag *parentTag)
|
||||
{
|
||||
if (parentTag->contains(L"abilities"))
|
||||
{
|
||||
CompoundTag *tag = parentTag->getCompound(L"abilities");
|
||||
|
||||
invulnerable = tag->getBoolean(L"invulnerable");
|
||||
flying = tag->getBoolean(L"flying");
|
||||
mayfly = tag->getBoolean(L"mayfly");
|
||||
instabuild = tag->getBoolean(L"instabuild");
|
||||
|
||||
if (tag->contains(L"flySpeed"))
|
||||
{
|
||||
flyingSpeed = tag->getFloat(L"flySpeed");
|
||||
walkingSpeed = tag->getFloat(L"walkSpeed");
|
||||
}
|
||||
if (tag->contains(L"mayBuild"))
|
||||
{
|
||||
mayBuild = tag->getBoolean(L"mayBuild");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float Abilities::getFlyingSpeed()
|
||||
{
|
||||
return flyingSpeed;
|
||||
}
|
||||
|
||||
void Abilities::setFlyingSpeed(float value)
|
||||
{
|
||||
this->flyingSpeed = value;
|
||||
}
|
||||
|
||||
float Abilities::getWalkingSpeed()
|
||||
{
|
||||
return walkingSpeed;
|
||||
}
|
||||
|
||||
void Abilities::setWalkingSpeed(float value)
|
||||
{
|
||||
this->walkingSpeed = value;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
class CompoundTag;
|
||||
|
||||
class Abilities
|
||||
{
|
||||
public:
|
||||
bool invulnerable;
|
||||
bool flying;
|
||||
bool mayfly;
|
||||
bool instabuild;
|
||||
bool mayBuild;
|
||||
|
||||
private:
|
||||
float flyingSpeed;
|
||||
float walkingSpeed;
|
||||
|
||||
public:
|
||||
#ifdef _DEBUG_MENUS_ENABLED
|
||||
bool debugflying;
|
||||
#endif
|
||||
|
||||
Abilities();
|
||||
|
||||
void addSaveData(CompoundTag *parentTag);
|
||||
void loadSaveData(CompoundTag *parentTag);
|
||||
|
||||
float getFlyingSpeed();
|
||||
void setFlyingSpeed(float value);
|
||||
float getWalkingSpeed();
|
||||
void setWalkingSpeed(float value);
|
||||
};
|
||||
@@ -0,0 +1,537 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.entity.player.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "Slot.h"
|
||||
#include "AbstractContainerMenu.h"
|
||||
|
||||
// 4J Stu - The java does not have ctor here (being an abstract) but we need one to initialise the member variables
|
||||
// TODO Make sure all derived classes also call this
|
||||
AbstractContainerMenu::AbstractContainerMenu()
|
||||
{
|
||||
lastSlots = new vector<shared_ptr<ItemInstance> >();
|
||||
slots = new vector<Slot *>();
|
||||
containerId = 0;
|
||||
|
||||
changeUid = 0;
|
||||
m_bNeedsRendered = false;
|
||||
|
||||
containerListeners = new vector<ContainerListener *>();
|
||||
}
|
||||
|
||||
AbstractContainerMenu::~AbstractContainerMenu()
|
||||
{
|
||||
delete lastSlots;
|
||||
for( unsigned int i = 0; i < slots->size(); i++ )
|
||||
{
|
||||
delete slots->at(i);
|
||||
}
|
||||
delete slots;
|
||||
delete containerListeners;
|
||||
}
|
||||
|
||||
Slot *AbstractContainerMenu::addSlot(Slot *slot)
|
||||
{
|
||||
slot->index = (int)slots->size();
|
||||
slots->push_back(slot);
|
||||
lastSlots->push_back(nullptr);
|
||||
return slot;
|
||||
}
|
||||
|
||||
|
||||
void AbstractContainerMenu::addSlotListener(ContainerListener *listener)
|
||||
{
|
||||
// TODO 4J Add exceptions
|
||||
/*
|
||||
if (containerListeners->contains(listener)) {
|
||||
throw new IllegalArgumentException("Listener already listening");
|
||||
}
|
||||
*/
|
||||
containerListeners->push_back(listener);
|
||||
|
||||
|
||||
vector<shared_ptr<ItemInstance> > *items = getItems();
|
||||
listener->refreshContainer(this, items);
|
||||
delete items;
|
||||
broadcastChanges();
|
||||
}
|
||||
|
||||
vector<shared_ptr<ItemInstance> > *AbstractContainerMenu::getItems()
|
||||
{
|
||||
vector<shared_ptr<ItemInstance> > *items = new vector<shared_ptr<ItemInstance> >();
|
||||
AUTO_VAR(itEnd, slots->end());
|
||||
for (AUTO_VAR(it, slots->begin()); it != itEnd; it++)
|
||||
{
|
||||
items->push_back((*it)->getItem());
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
void AbstractContainerMenu::sendData(int id, int value)
|
||||
{
|
||||
AUTO_VAR(itEnd, containerListeners->end());
|
||||
for (AUTO_VAR(it, containerListeners->begin()); it != itEnd; it++)
|
||||
{
|
||||
(*it)->setContainerData(this, id, value);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractContainerMenu::broadcastChanges()
|
||||
{
|
||||
for (unsigned int i = 0; i < slots->size(); i++)
|
||||
{
|
||||
shared_ptr<ItemInstance> current = slots->at(i)->getItem();
|
||||
shared_ptr<ItemInstance> expected = lastSlots->at(i);
|
||||
if (!ItemInstance::matches(expected, current))
|
||||
{
|
||||
expected = current == NULL ? nullptr : current->copy();
|
||||
(*lastSlots)[i] = expected;
|
||||
m_bNeedsRendered = true;
|
||||
|
||||
AUTO_VAR(itEnd, containerListeners->end());
|
||||
for (AUTO_VAR(it, containerListeners->begin()); it != itEnd; it++)
|
||||
{
|
||||
(*it)->slotChanged(this, i, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AbstractContainerMenu::needsRendered()
|
||||
{
|
||||
bool needsRendered = m_bNeedsRendered;
|
||||
m_bNeedsRendered = false;
|
||||
|
||||
for (unsigned int i = 0; i < slots->size(); i++)
|
||||
{
|
||||
shared_ptr<ItemInstance> current = slots->at(i)->getItem();
|
||||
shared_ptr<ItemInstance> expected = lastSlots->at(i);
|
||||
if (!ItemInstance::matches(expected, current))
|
||||
{
|
||||
expected = current == NULL ? nullptr : current->copy();
|
||||
(*lastSlots)[i] = expected;
|
||||
needsRendered = true;
|
||||
}
|
||||
}
|
||||
|
||||
return needsRendered;
|
||||
}
|
||||
|
||||
bool AbstractContainerMenu::clickMenuButton(shared_ptr<Player> player, int buttonId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Slot *AbstractContainerMenu::getSlotFor(shared_ptr<Container> c, int index)
|
||||
{
|
||||
AUTO_VAR(itEnd, slots->end());
|
||||
for (AUTO_VAR(it, slots->begin()); it != itEnd; it++)
|
||||
{
|
||||
Slot *slot = *it; //slots->at(i);
|
||||
if (slot->isAt(c, index))
|
||||
{
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Slot *AbstractContainerMenu::getSlot(int index)
|
||||
{
|
||||
return slots->at(index);
|
||||
}
|
||||
|
||||
shared_ptr<ItemInstance> AbstractContainerMenu::quickMoveStack(shared_ptr<Player> player, int slotIndex)
|
||||
{
|
||||
Slot *slot = slots->at(slotIndex);
|
||||
if (slot != NULL)
|
||||
{
|
||||
return slot->getItem();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr<Player> player)
|
||||
{
|
||||
shared_ptr<ItemInstance> clickedEntity = nullptr;
|
||||
shared_ptr<Inventory> inventory = player->inventory;
|
||||
|
||||
if ((clickType == CLICK_PICKUP || clickType == CLICK_QUICK_MOVE) && (buttonNum == 0 || buttonNum == 1))
|
||||
{
|
||||
if (slotIndex == CLICKED_OUTSIDE)
|
||||
{
|
||||
if (inventory->getCarried() != NULL)
|
||||
{
|
||||
if (slotIndex == CLICKED_OUTSIDE)
|
||||
{
|
||||
if (buttonNum == 0)
|
||||
{
|
||||
player->drop(inventory->getCarried());
|
||||
inventory->setCarried(nullptr);
|
||||
}
|
||||
if (buttonNum == 1)
|
||||
{
|
||||
player->drop(inventory->getCarried()->remove(1));
|
||||
if (inventory->getCarried()->count == 0) inventory->setCarried(nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (clickType == CLICK_QUICK_MOVE)
|
||||
{
|
||||
Slot *slot = slots->at(slotIndex);
|
||||
if(slot != NULL && slot->mayPickup(player))
|
||||
{
|
||||
shared_ptr<ItemInstance> piiClicked = quickMoveStack(player, slotIndex);
|
||||
if (piiClicked != NULL)
|
||||
{
|
||||
//int oldSize = piiClicked->count; // 4J - Commented 1.8.2 and replaced with below
|
||||
int oldType = piiClicked->id;
|
||||
|
||||
clickedEntity = piiClicked->copy();
|
||||
|
||||
if (slot != NULL)
|
||||
{
|
||||
if (slot->getItem() != NULL && slot->getItem()->id == oldType)
|
||||
{
|
||||
// 4J Stu - Brought forward loopClick from 1.2 to fix infinite recursion bug in creative
|
||||
loopClick(slotIndex, buttonNum, true, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (slotIndex < 0) return nullptr;
|
||||
|
||||
Slot *slot = slots->at(slotIndex);
|
||||
if (slot != NULL)
|
||||
{
|
||||
shared_ptr<ItemInstance> clicked = slot->getItem();
|
||||
shared_ptr<ItemInstance> carried = inventory->getCarried();
|
||||
|
||||
if (clicked != NULL)
|
||||
{
|
||||
clickedEntity = clicked->copy();
|
||||
}
|
||||
|
||||
if (clicked == NULL)
|
||||
{
|
||||
if (carried != NULL && slot->mayPlace(carried))
|
||||
{
|
||||
int c = buttonNum == 0 ? carried->count : 1;
|
||||
if (c > slot->getMaxStackSize())
|
||||
{
|
||||
c = slot->getMaxStackSize();
|
||||
}
|
||||
slot->set(carried->remove(c));
|
||||
if (carried->count == 0)
|
||||
{
|
||||
inventory->setCarried(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 4J Added for dyable armour and combinining damaged items
|
||||
else if (buttonNum == 1 && mayCombine(slot, carried))
|
||||
{
|
||||
shared_ptr<ItemInstance> combined = slot->combine(carried);
|
||||
if(combined != NULL)
|
||||
{
|
||||
slot->set(combined);
|
||||
if(!player->abilities.instabuild) carried->remove(1);
|
||||
if (carried->count == 0)
|
||||
{
|
||||
inventory->setCarried(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (slot->mayPickup(player))
|
||||
{
|
||||
if (carried == NULL)
|
||||
{
|
||||
// pick up to empty hand
|
||||
int c = buttonNum == 0 ? clicked->count : (clicked->count + 1) / 2;
|
||||
shared_ptr<ItemInstance> removed = slot->remove(c);
|
||||
|
||||
inventory->setCarried(removed);
|
||||
if (clicked->count == 0)
|
||||
{
|
||||
slot->set(nullptr);
|
||||
}
|
||||
slot->onTake(player, inventory->getCarried());
|
||||
}
|
||||
else if (slot->mayPlace(carried))
|
||||
{
|
||||
// put down and/or pick up
|
||||
if (clicked->id != carried->id || clicked->getAuxValue() != carried->getAuxValue() || !ItemInstance::tagMatches(clicked, carried))
|
||||
{
|
||||
// no match, replace
|
||||
if (carried->count <= slot->getMaxStackSize())
|
||||
{
|
||||
slot->set(carried);
|
||||
inventory->setCarried(clicked);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// match, attempt to fill slot
|
||||
int c = buttonNum == 0 ? carried->count : 1;
|
||||
if (c > slot->getMaxStackSize() - clicked->count)
|
||||
{
|
||||
c = slot->getMaxStackSize() - clicked->count;
|
||||
}
|
||||
if (c > carried->getMaxStackSize() - clicked->count)
|
||||
{
|
||||
c = carried->getMaxStackSize() - clicked->count;
|
||||
}
|
||||
carried->remove(c);
|
||||
if (carried->count == 0)
|
||||
{
|
||||
inventory->setCarried(nullptr);
|
||||
}
|
||||
clicked->count += c;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// pick up to non-empty hand
|
||||
if (clicked->id == carried->id && carried->getMaxStackSize() > 1 && (!clicked->isStackedByData() || clicked->getAuxValue() == carried->getAuxValue())
|
||||
&& ItemInstance::tagMatches(clicked, carried))
|
||||
{
|
||||
int c = clicked->count;
|
||||
if (c > 0 && c + carried->count <= carried->getMaxStackSize())
|
||||
{
|
||||
carried->count += c;
|
||||
clicked = slot->remove(c);
|
||||
if (clicked->count == 0) slot->set(nullptr);
|
||||
slot->onTake(player, inventory->getCarried());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
slot->setChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (clickType == CLICK_SWAP && buttonNum >= 0 && buttonNum < 9)
|
||||
{
|
||||
Slot *slot = slots->at(slotIndex);
|
||||
if (slot->mayPickup(player))
|
||||
{
|
||||
shared_ptr<ItemInstance> current = inventory->getItem(buttonNum);
|
||||
bool canMove = current == NULL || (slot->container == inventory && slot->mayPlace(current));
|
||||
int freeSlot = -1;
|
||||
|
||||
if (!canMove)
|
||||
{
|
||||
freeSlot = inventory->getFreeSlot();
|
||||
canMove |= freeSlot > -1;
|
||||
}
|
||||
|
||||
if (slot->hasItem() && canMove)
|
||||
{
|
||||
shared_ptr<ItemInstance> taking = slot->getItem();
|
||||
inventory->setItem(buttonNum, taking);
|
||||
|
||||
if ((slot->container == inventory && slot->mayPlace(current)) || current == NULL)
|
||||
{
|
||||
slot->remove(taking->count);
|
||||
slot->set(current);
|
||||
slot->onTake(player, taking);
|
||||
}
|
||||
else if (freeSlot > -1)
|
||||
{
|
||||
inventory->add(current);
|
||||
slot->remove(taking->count);
|
||||
slot->set(nullptr);
|
||||
slot->onTake(player, taking);
|
||||
}
|
||||
}
|
||||
else if (!slot->hasItem() && current != NULL && slot->mayPlace(current))
|
||||
{
|
||||
inventory->setItem(buttonNum, nullptr);
|
||||
slot->set(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (clickType == CLICK_CLONE && player->abilities.instabuild && inventory->getCarried() == NULL && slotIndex >= 0)
|
||||
{
|
||||
Slot *slot = slots->at(slotIndex);
|
||||
if (slot != NULL && slot->hasItem())
|
||||
{
|
||||
shared_ptr<ItemInstance> copy = slot->getItem()->copy();
|
||||
copy->count = copy->getMaxStackSize();
|
||||
inventory->setCarried(copy);
|
||||
}
|
||||
}
|
||||
return clickedEntity;
|
||||
}
|
||||
|
||||
// 4J Stu - Brought forward from 1.2 to fix infinite recursion bug in creative
|
||||
void AbstractContainerMenu::loopClick(int slotIndex, int buttonNum, bool quickKeyHeld, shared_ptr<Player> player)
|
||||
{
|
||||
clicked(slotIndex, buttonNum, CLICK_QUICK_MOVE, player);
|
||||
}
|
||||
|
||||
bool AbstractContainerMenu::mayCombine(Slot *slot, shared_ptr<ItemInstance> item)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AbstractContainerMenu::removed(shared_ptr<Player> player)
|
||||
{
|
||||
shared_ptr<Inventory> inventory = player->inventory;
|
||||
if (inventory->getCarried() != NULL)
|
||||
{
|
||||
player->drop(inventory->getCarried());
|
||||
inventory->setCarried(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractContainerMenu::slotsChanged()// 4J used to take a shared_ptr<Container> but wasn't using it, so removed to simplify things
|
||||
{
|
||||
broadcastChanges();
|
||||
}
|
||||
|
||||
bool AbstractContainerMenu::isPauseScreen()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AbstractContainerMenu::setItem(unsigned int slot, shared_ptr<ItemInstance> item)
|
||||
{
|
||||
getSlot(slot)->set(item);
|
||||
}
|
||||
|
||||
void AbstractContainerMenu::setAll(ItemInstanceArray *items)
|
||||
{
|
||||
for (unsigned int i = 0; i < items->length; i++)
|
||||
{
|
||||
getSlot(i)->set( (*items)[i] );
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractContainerMenu::setData(int id, int value)
|
||||
{
|
||||
}
|
||||
|
||||
short AbstractContainerMenu::backup(shared_ptr<Inventory> inventory)
|
||||
{
|
||||
changeUid++;
|
||||
return changeUid;
|
||||
}
|
||||
|
||||
bool AbstractContainerMenu::isSynched(shared_ptr<Player> player)
|
||||
{
|
||||
return !(unSynchedPlayers.find(player) != unSynchedPlayers.end());
|
||||
}
|
||||
|
||||
void AbstractContainerMenu::setSynched(shared_ptr<Player> player, bool synched)
|
||||
{
|
||||
if (synched)
|
||||
{
|
||||
AUTO_VAR(it, unSynchedPlayers.find(player));
|
||||
|
||||
if(it != unSynchedPlayers.end()) unSynchedPlayers.erase( it );
|
||||
}
|
||||
else
|
||||
{
|
||||
unSynchedPlayers.insert(player);
|
||||
}
|
||||
}
|
||||
|
||||
// 4J Stu - Brought a few changes in this function forward from 1.2 to make it return a bool
|
||||
bool AbstractContainerMenu::moveItemStackTo(shared_ptr<ItemInstance> itemStack, int startSlot, int endSlot, bool backwards)
|
||||
{
|
||||
bool anythingChanged = false;
|
||||
|
||||
int destSlot = startSlot;
|
||||
if (backwards)
|
||||
{
|
||||
destSlot = endSlot - 1;
|
||||
}
|
||||
|
||||
// find stackable slots first
|
||||
if (itemStack->isStackable())
|
||||
{
|
||||
while (itemStack->count > 0 && ((!backwards && destSlot < endSlot) || (backwards && destSlot >= startSlot)))
|
||||
{
|
||||
|
||||
Slot *slot = slots->at(destSlot);
|
||||
shared_ptr<ItemInstance> target = slot->getItem();
|
||||
if (target != NULL && target->id == itemStack->id && (!itemStack->isStackedByData() || itemStack->getAuxValue() == target->getAuxValue())
|
||||
&& ItemInstance::tagMatches(itemStack, target) )
|
||||
{
|
||||
int totalStack = target->count + itemStack->count;
|
||||
if (totalStack <= itemStack->getMaxStackSize())
|
||||
{
|
||||
itemStack->count = 0;
|
||||
target->count = totalStack;
|
||||
slot->setChanged();
|
||||
anythingChanged = true;
|
||||
}
|
||||
else if (target->count < itemStack->getMaxStackSize())
|
||||
{
|
||||
itemStack->count -= (itemStack->getMaxStackSize() - target->count);
|
||||
target->count = itemStack->getMaxStackSize();
|
||||
slot->setChanged();
|
||||
anythingChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (backwards)
|
||||
{
|
||||
destSlot--;
|
||||
}
|
||||
else
|
||||
{
|
||||
destSlot++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find empty slot
|
||||
if (itemStack->count > 0)
|
||||
{
|
||||
if (backwards)
|
||||
{
|
||||
destSlot = endSlot - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
destSlot = startSlot;
|
||||
}
|
||||
while ((!backwards && destSlot < endSlot) || (backwards && destSlot >= startSlot))
|
||||
{
|
||||
Slot *slot = slots->at(destSlot);
|
||||
shared_ptr<ItemInstance> target = slot->getItem();
|
||||
|
||||
if (target == NULL)
|
||||
{
|
||||
slot->set(itemStack->copy());
|
||||
slot->setChanged();
|
||||
itemStack->count = 0;
|
||||
anythingChanged = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (backwards)
|
||||
{
|
||||
destSlot--;
|
||||
}
|
||||
else
|
||||
{
|
||||
destSlot++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return anythingChanged;
|
||||
}
|
||||
|
||||
bool AbstractContainerMenu::isOverrideResultClick(int slotNum, int buttonNum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include "Player.h"
|
||||
#include "net.minecraft.world.inventory.ContainerListener.h"
|
||||
using net_minecraft_world_inventory::ContainerListener;
|
||||
|
||||
class Inventory;
|
||||
class Slot;
|
||||
class Item;
|
||||
class ItemInstance;
|
||||
class Container;
|
||||
|
||||
class AbstractContainerMenu
|
||||
{
|
||||
public:
|
||||
static const int CLICKED_OUTSIDE = -999;
|
||||
|
||||
static const int CLICK_PICKUP = 0;
|
||||
static const int CLICK_QUICK_MOVE = 1;
|
||||
static const int CLICK_SWAP = 2;
|
||||
static const int CLICK_CLONE = 3;
|
||||
|
||||
// 4J Stu - Added these to fix problem with items picked up while in the creative menu replacing slots in the creative menu
|
||||
static const int CONTAINER_ID_CARRIED = -1;
|
||||
static const int CONTAINER_ID_INVENTORY = 0;
|
||||
static const int CONTAINER_ID_CREATIVE = -2;
|
||||
|
||||
vector<shared_ptr<ItemInstance> > *lastSlots;
|
||||
vector<Slot *> *slots;
|
||||
int containerId;
|
||||
|
||||
private:
|
||||
short changeUid;
|
||||
bool m_bNeedsRendered; // 4J added
|
||||
|
||||
protected:
|
||||
vector<ContainerListener *> *containerListeners;
|
||||
|
||||
// 4J Stu - The java does not have ctor here (being an abstract) but we need one to initialise the member variables
|
||||
// TODO Make sure all derived classes also call this
|
||||
AbstractContainerMenu();
|
||||
|
||||
Slot *addSlot(Slot *slot);
|
||||
|
||||
public:
|
||||
virtual ~AbstractContainerMenu();
|
||||
virtual void addSlotListener(ContainerListener *listener);
|
||||
vector<shared_ptr<ItemInstance> > *getItems();
|
||||
void sendData(int id, int value);
|
||||
virtual void broadcastChanges();
|
||||
virtual bool needsRendered();
|
||||
virtual bool clickMenuButton(shared_ptr<Player> player, int buttonId);
|
||||
Slot *getSlotFor(shared_ptr<Container> c, int index);
|
||||
Slot *getSlot(int index);
|
||||
virtual shared_ptr<ItemInstance> quickMoveStack(shared_ptr<Player> player, int slotIndex);
|
||||
virtual shared_ptr<ItemInstance> clicked(int slotIndex, int buttonNum, int clickType, shared_ptr<Player> player);
|
||||
virtual bool mayCombine(Slot *slot, shared_ptr<ItemInstance> item);
|
||||
protected:
|
||||
virtual void loopClick(int slotIndex, int buttonNum, bool quickKeyHeld, shared_ptr<Player> player);
|
||||
public:
|
||||
virtual void removed(shared_ptr<Player> player);
|
||||
virtual void slotsChanged();// 4J used to take a shared_ptr<Container> container but wasn't using it, so removed to simplify things
|
||||
bool isPauseScreen();
|
||||
void setItem(unsigned int slot, shared_ptr<ItemInstance> item);
|
||||
void setAll(ItemInstanceArray *items);
|
||||
virtual void setData(int id, int value);
|
||||
short backup(shared_ptr<Inventory> inventory);
|
||||
|
||||
private:
|
||||
unordered_set<shared_ptr<Player> , PlayerKeyHash, PlayerKeyEq> unSynchedPlayers;
|
||||
|
||||
public:
|
||||
bool isSynched(shared_ptr<Player> player);
|
||||
void setSynched(shared_ptr<Player> player, bool synched);
|
||||
virtual bool stillValid(shared_ptr<Player> player) = 0;
|
||||
|
||||
// 4J Stu Added for UI
|
||||
unsigned int getSize() { return (unsigned int)slots->size(); }
|
||||
|
||||
|
||||
protected:
|
||||
// 4J Stu - Changes to return bool brought forward from 1.2
|
||||
bool moveItemStackTo(shared_ptr<ItemInstance> itemStack, int startSlot, int endSlot, bool backwards);
|
||||
|
||||
public:
|
||||
virtual bool isOverrideResultClick(int slotNum, int buttonNum);
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.locale.h"
|
||||
#include "ItemInstance.h"
|
||||
#include "Achievements.h"
|
||||
#include "DescFormatter.h"
|
||||
#include "Achievement.h"
|
||||
|
||||
void Achievement::_init()
|
||||
{
|
||||
isGoldenVar = false;
|
||||
|
||||
if (x < Achievements::xMin) Achievements::xMin = x;
|
||||
if (y < Achievements::yMin) Achievements::yMin = y;
|
||||
if (x > Achievements::xMax) Achievements::xMax = x;
|
||||
if (y > Achievements::yMax) Achievements::yMax = y;
|
||||
}
|
||||
|
||||
Achievement::Achievement(int id, const wstring& name, int x, int y, Item *icon, Achievement *requires)
|
||||
: Stat( Achievements::ACHIEVEMENT_OFFSET + id, I18n::get(wstring(L"achievement.").append(name)) ), desc( I18n::get(wstring(L"achievement.").append(name).append(L".desc"))), icon( new ItemInstance(icon) ), x(x), y(y), requires(requires)
|
||||
{
|
||||
}
|
||||
|
||||
Achievement::Achievement(int id, const wstring& name, int x, int y, Tile *icon, Achievement *requires)
|
||||
: Stat( Achievements::ACHIEVEMENT_OFFSET + id, I18n::get(wstring(L"achievement.").append(name)) ), desc( I18n::get(wstring(L"achievement.").append(name).append(L".desc"))), icon( new ItemInstance(icon) ), x(x), y(y), requires(requires)
|
||||
{
|
||||
}
|
||||
|
||||
Achievement::Achievement(int id, const wstring& name, int x, int y, shared_ptr<ItemInstance> icon, Achievement *requires)
|
||||
: Stat( Achievements::ACHIEVEMENT_OFFSET + id, I18n::get(wstring(L"achievement.").append(name)) ), desc( I18n::get(wstring(L"achievement.").append(name).append(L".desc"))), icon(icon), x(x), y(y), requires(requires)
|
||||
{
|
||||
}
|
||||
|
||||
Achievement *Achievement::setAwardLocallyOnly()
|
||||
{
|
||||
awardLocallyOnly = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
Achievement *Achievement::setGolden()
|
||||
{
|
||||
isGoldenVar = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
Achievement *Achievement::postConstruct()
|
||||
{
|
||||
Stat::postConstruct();
|
||||
|
||||
Achievements::achievements->push_back(this);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
bool Achievement::isAchievement()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
wstring Achievement::getDescription()
|
||||
{
|
||||
if (descFormatter != NULL)
|
||||
{
|
||||
return descFormatter->format(desc);
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
Achievement *Achievement::setDescFormatter(DescFormatter *descFormatter)
|
||||
{
|
||||
this->descFormatter = descFormatter;
|
||||
return this;
|
||||
}
|
||||
|
||||
bool Achievement::isGolden()
|
||||
{
|
||||
return isGoldenVar;
|
||||
}
|
||||
|
||||
int Achievement::getAchievementID()
|
||||
{
|
||||
return id - Achievements::ACHIEVEMENT_OFFSET;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include "Stat.h"
|
||||
|
||||
class DescFormatter;
|
||||
|
||||
class Achievement : public Stat
|
||||
{
|
||||
public:
|
||||
const int x, y;
|
||||
Achievement *requires;
|
||||
|
||||
private:
|
||||
const wstring desc;
|
||||
DescFormatter *descFormatter;
|
||||
|
||||
public:
|
||||
const shared_ptr<ItemInstance> icon;
|
||||
|
||||
private:
|
||||
bool isGoldenVar;
|
||||
void _init();
|
||||
|
||||
public:
|
||||
Achievement(int id, const wstring& name, int x, int y, Item *icon, Achievement *requires);
|
||||
Achievement(int id, const wstring& name, int x, int y, Tile *icon, Achievement *requires);
|
||||
Achievement(int id, const wstring& name, int x, int y, shared_ptr<ItemInstance> icon, Achievement *requires);
|
||||
|
||||
Achievement *setAwardLocallyOnly();
|
||||
Achievement *setGolden();
|
||||
Achievement *postConstruct();
|
||||
bool isAchievement();
|
||||
wstring getDescription();
|
||||
Achievement *setDescFormatter(DescFormatter *descFormatter);
|
||||
bool isGolden();
|
||||
int getAchievementID();
|
||||
};
|
||||
@@ -0,0 +1,183 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.stats.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "Achievement.h"
|
||||
#include "Achievements.h"
|
||||
|
||||
|
||||
const int Achievements::ACHIEVEMENT_OFFSET = 0x500000;
|
||||
|
||||
// maximum position of achievements (min and max)
|
||||
|
||||
int Achievements::xMin = 4294967295; // 4J Stu Was 4294967296 which is 1 larger than maxint. Hopefully no side effects
|
||||
int Achievements::yMin = 4294967295; // 4J Stu Was 4294967296 which is 1 larger than maxint. Hopefully no side effects
|
||||
int Achievements::xMax = 0;
|
||||
int Achievements::yMax = 0;
|
||||
|
||||
vector<Achievement *> *Achievements::achievements = new vector<Achievement *>;
|
||||
|
||||
Achievement *Achievements::openInventory = NULL;
|
||||
Achievement *Achievements::mineWood = NULL;
|
||||
Achievement *Achievements::buildWorkbench = NULL;
|
||||
Achievement *Achievements::buildPickaxe = NULL;
|
||||
Achievement *Achievements::buildFurnace = NULL;
|
||||
Achievement *Achievements::acquireIron = NULL;
|
||||
Achievement *Achievements::buildHoe = NULL;
|
||||
Achievement *Achievements::makeBread = NULL;
|
||||
Achievement *Achievements::bakeCake = NULL;
|
||||
Achievement *Achievements::buildBetterPickaxe = NULL;
|
||||
Achievement *Achievements::cookFish = NULL;
|
||||
Achievement *Achievements::onARail = NULL;
|
||||
Achievement *Achievements::buildSword = NULL;
|
||||
Achievement *Achievements::killEnemy = NULL;
|
||||
Achievement *Achievements::killCow = NULL;
|
||||
Achievement *Achievements::flyPig = NULL;
|
||||
|
||||
Achievement *Achievements::snipeSkeleton = NULL;
|
||||
Achievement *Achievements::diamonds = NULL;
|
||||
//Achievement *Achievements::portal = NULL;
|
||||
Achievement *Achievements::ghast = NULL;
|
||||
Achievement *Achievements::blazeRod = NULL;
|
||||
Achievement *Achievements::potion = NULL;
|
||||
Achievement *Achievements::theEnd = NULL;
|
||||
Achievement *Achievements::winGame = NULL;
|
||||
Achievement *Achievements::enchantments = NULL;
|
||||
//Achievement *Achievements::overkill = NULL;
|
||||
//Achievement *Achievements::bookcase = NULL;
|
||||
|
||||
// 4J : WESTY : Added new acheivements.
|
||||
Achievement *Achievements::leaderOfThePack = NULL;
|
||||
Achievement *Achievements::MOARTools = NULL;
|
||||
Achievement *Achievements::dispenseWithThis = NULL;
|
||||
Achievement *Achievements::InToTheNether = NULL;
|
||||
|
||||
// 4J : WESTY : Added other awards.
|
||||
Achievement *Achievements::socialPost = NULL;
|
||||
Achievement *Achievements::eatPorkChop = NULL;
|
||||
Achievement *Achievements::play100Days = NULL;
|
||||
Achievement *Achievements::arrowKillCreeper = NULL;
|
||||
Achievement *Achievements::mine100Blocks = NULL;
|
||||
Achievement *Achievements::kill10Creepers = NULL;
|
||||
|
||||
#ifdef _EXTENDED_ACHIEVEMENTS
|
||||
Achievement *Achievements::overkill = NULL; // Restored old achivements.
|
||||
Achievement *Achievements::bookcase = NULL; // Restored old achivements.
|
||||
|
||||
// 4J-JEV: New Achievements for Orbis.
|
||||
Achievement *Achievements::adventuringTime = NULL;
|
||||
Achievement *Achievements::repopulation = NULL;
|
||||
//Achievement *Achievements::porkChop = NULL;
|
||||
Achievement *Achievements::diamondsToYou = NULL;
|
||||
//Achievement *Achievements::passingTheTime = NULL;
|
||||
//Achievement *Achievements::archer = NULL;
|
||||
Achievement *Achievements::theHaggler = NULL;
|
||||
Achievement *Achievements::potPlanter = NULL;
|
||||
Achievement *Achievements::itsASign = NULL;
|
||||
Achievement *Achievements::ironBelly = NULL;
|
||||
Achievement *Achievements::haveAShearfulDay = NULL;
|
||||
Achievement *Achievements::rainbowCollection = NULL;
|
||||
Achievement *Achievements::stayinFrosty = NULL;
|
||||
Achievement *Achievements::chestfulOfCobblestone = NULL;
|
||||
Achievement *Achievements::renewableEnergy = NULL;
|
||||
Achievement *Achievements::musicToMyEars = NULL;
|
||||
Achievement *Achievements::bodyGuard = NULL;
|
||||
Achievement *Achievements::ironMan = NULL;
|
||||
Achievement *Achievements::zombieDoctor = NULL;
|
||||
Achievement *Achievements::lionTamer = NULL;
|
||||
#endif
|
||||
|
||||
void Achievements::staticCtor()
|
||||
{
|
||||
Achievements::openInventory = (new Achievement(eAward_TakingInventory, L"openInventory", 0, 0, Item::book, NULL))->setAwardLocallyOnly()->postConstruct();
|
||||
Achievements::mineWood = (new Achievement(eAward_GettingWood, L"mineWood", 2, 1, Tile::treeTrunk, (Achievement *) openInventory))->postConstruct();
|
||||
Achievements::buildWorkbench = (new Achievement(eAward_Benchmarking, L"buildWorkBench", 4, -1, Tile::workBench, (Achievement *) mineWood))->postConstruct();
|
||||
Achievements::buildPickaxe = (new Achievement(eAward_TimeToMine, L"buildPickaxe", 4, 2, Item::pickAxe_wood, (Achievement *) buildWorkbench))->postConstruct();
|
||||
Achievements::buildFurnace = (new Achievement(eAward_HotTopic, L"buildFurnace", 3, 4, Tile::furnace_lit, (Achievement *) buildPickaxe))->postConstruct();
|
||||
Achievements::acquireIron = (new Achievement(eAward_AquireHardware, L"acquireIron", 1, 4, Item::ironIngot, (Achievement *) buildFurnace))->postConstruct();
|
||||
Achievements::buildHoe = (new Achievement(eAward_TimeToFarm, L"buildHoe", 2, -3, Item::hoe_wood, (Achievement *) buildWorkbench))->postConstruct();
|
||||
Achievements::makeBread = (new Achievement(eAward_BakeBread, L"makeBread", -1, -3, Item::bread, (Achievement *) buildHoe))->postConstruct();
|
||||
Achievements::bakeCake = (new Achievement(eAward_TheLie, L"bakeCake", 0, -5, Item::cake, (Achievement *) buildHoe))->postConstruct();
|
||||
Achievements::buildBetterPickaxe = (new Achievement(eAward_GettingAnUpgrade, L"buildBetterPickaxe", 6, 2, Item::pickAxe_stone, (Achievement *) buildPickaxe))->postConstruct();
|
||||
Achievements::cookFish = (new Achievement(eAward_DeliciousFish, L"cookFish", 2, 6, Item::fish_cooked, (Achievement *) buildFurnace))->postConstruct();
|
||||
Achievements::onARail = (new Achievement(eAward_OnARail, L"onARail", 2, 3, Tile::rail, (Achievement *) acquireIron))->setGolden()->postConstruct();
|
||||
Achievements::buildSword = (new Achievement(eAward_TimeToStrike, L"buildSword", 6, -1, Item::sword_wood, (Achievement *) buildWorkbench))->postConstruct();
|
||||
Achievements::killEnemy = (new Achievement(eAward_MonsterHunter, L"killEnemy", 8, -1, Item::bone, (Achievement *) buildSword))->postConstruct();
|
||||
Achievements::killCow = (new Achievement(eAward_CowTipper, L"killCow", 7, -3, Item::leather, (Achievement *) buildSword))->postConstruct();
|
||||
Achievements::flyPig = (new Achievement(eAward_WhenPigsFly, L"flyPig", 8, -4, Item::saddle, (Achievement *) killCow))->setGolden()->postConstruct();
|
||||
|
||||
// 4J Stu - The order of these achievemnts is very important, as they map directly to data stored in the profile data. New achievements should be added at the end.
|
||||
|
||||
// 4J : WESTY : Added new achievements. Note, params "x", "y", "icon" and "requires" are ignored on xbox.
|
||||
Achievements::leaderOfThePack = (new Achievement(eAward_LeaderOfThePack, L"leaderOfThePack", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->setAwardLocallyOnly()->postConstruct();
|
||||
Achievements::MOARTools = (new Achievement(eAward_MOARTools, L"MOARTools", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->setAwardLocallyOnly()->postConstruct();
|
||||
Achievements::dispenseWithThis = (new Achievement(eAward_DispenseWithThis, L"dispenseWithThis", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->postConstruct();
|
||||
Achievements::InToTheNether = (new Achievement(eAward_InToTheNether, L"InToTheNether", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->postConstruct();
|
||||
|
||||
// 4J : WESTY : Added other awards.
|
||||
Achievements::mine100Blocks = (new Achievement(eAward_mine100Blocks, L"mine100Blocks", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->setAwardLocallyOnly()->postConstruct();
|
||||
Achievements::kill10Creepers = (new Achievement(eAward_kill10Creepers, L"kill10Creepers", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->setAwardLocallyOnly()->postConstruct();
|
||||
#ifdef _EXTENDED_ACHIEVEMENTS
|
||||
Achievements::eatPorkChop = (new Achievement(eAward_eatPorkChop, L"eatPorkChop", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->setAwardLocallyOnly()->postConstruct();
|
||||
#else
|
||||
Achievements::eatPorkChop = (new Achievement(eAward_eatPorkChop, L"eatPorkChop", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->postConstruct();
|
||||
#endif
|
||||
Achievements::play100Days = (new Achievement(eAward_play100Days, L"play100Days", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->setAwardLocallyOnly()->postConstruct();
|
||||
Achievements::arrowKillCreeper = (new Achievement(eAward_arrowKillCreeper, L"arrowKillCreeper", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->postConstruct();
|
||||
Achievements::socialPost = (new Achievement(eAward_socialPost, L"socialPost", 0, 0, Tile::treeTrunk, (Achievement *) buildSword))->postConstruct();
|
||||
|
||||
// WARNING: NO NEW ACHIEVMENTS CAN BE ADDED HERE
|
||||
// These stats (achievements) are directly followed by new stats/achievements in the profile data, so cannot be changed without migrating the profile data
|
||||
|
||||
// 4J Stu - All new Java achievements removed to stop them using the profile data
|
||||
|
||||
// 4J Stu - This achievment added in 1.8.2, but does not map to any Xbox achievements
|
||||
Achievements::snipeSkeleton = (new Achievement(eAward_snipeSkeleton, L"snipeSkeleton", 7, 0, Item::bow, (Achievement *) killEnemy))->setGolden()->postConstruct();
|
||||
|
||||
// 4J Stu - These added in 1.0.1, but do not map to any Xbox achievements
|
||||
Achievements::diamonds = (new Achievement(eAward_diamonds, L"diamonds", -1, 5, Item::diamond, (Achievement *) acquireIron) )->postConstruct();
|
||||
//Achievements::portal = (new Achievement(eAward_portal, L"portal", -1, 7, Tile::obsidian, (Achievement *)diamonds) )->postConstruct();
|
||||
Achievements::ghast = (new Achievement(eAward_ghast, L"ghast", -4, 8, Item::ghastTear, (Achievement *)ghast) )->setGolden()->postConstruct();
|
||||
Achievements::blazeRod = (new Achievement(eAward_blazeRod, L"blazeRod", 0, 9, Item::blazeRod, (Achievement *)blazeRod) )->postConstruct();
|
||||
Achievements::potion = (new Achievement(eAward_potion, L"potion", 2, 8, Item::potion, (Achievement *)potion) )->postConstruct();
|
||||
Achievements::theEnd = (new Achievement(eAward_theEnd, L"theEnd", 3, 10, Item::eyeOfEnder, (Achievement *)theEnd) )->setGolden()->postConstruct();
|
||||
Achievements::winGame = (new Achievement(eAward_winGame, L"theEnd2", 4, 13, Tile::dragonEgg, (Achievement *)winGame) )->setGolden()->postConstruct();
|
||||
Achievements::enchantments = (new Achievement(eAward_enchantments, L"enchantments", -4, 4, Tile::enchantTable, (Achievement *)enchantments) )->postConstruct();
|
||||
// Achievements::overkill = (new Achievement(eAward_overkill, L"overkill", -4, 1, Item::sword_diamond, (Achievement *)enchantments) )->setGolden()->postConstruct();
|
||||
// Achievements::bookcase = (new Achievement(eAward_bookcase, L"bookcase", -3, 6, Tile::bookshelf, (Achievement *)enchantments) )->postConstruct();
|
||||
|
||||
#ifdef _EXTENDED_ACHIEVEMENTS
|
||||
Achievements::overkill = (new Achievement(eAward_overkill, L"overkill", -4,1, Item::sword_diamond, (Achievement *)enchantments) )->setGolden()->postConstruct();
|
||||
Achievements::bookcase = (new Achievement(eAward_bookcase, L"bookcase", -3,6, Tile::bookshelf, (Achievement *)enchantments) )->postConstruct();
|
||||
|
||||
Achievements::adventuringTime = (new Achievement(eAward_adventuringTime, L"adventuringTime", 0,0, Tile::bookshelf, (Achievement*) NULL) )->setAwardLocallyOnly()->postConstruct();
|
||||
Achievements::repopulation = (new Achievement(eAward_repopulation, L"repopulation", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
//Achievements::porkChoop // // // // // //
|
||||
Achievements::diamondsToYou = (new Achievement(eAward_diamondsToYou, L"diamondsToYou", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
//Achievements::passingTheTime = (new Achievement(eAward_play100Days, L"passingTheTime", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
//Achievements::archer = (new Achievement(eAward_arrowKillCreeper, L"archer", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
Achievements::theHaggler = (new Achievement(eAward_theHaggler, L"theHaggler", 0,0, Tile::bookshelf, (Achievement*) NULL) )->setAwardLocallyOnly()->postConstruct();
|
||||
Achievements::potPlanter = (new Achievement(eAward_potPlanter, L"potPlanter", 0,0, Tile::bookshelf, (Achievement*) NULL) )->setAwardLocallyOnly()->postConstruct();
|
||||
Achievements::itsASign = (new Achievement(eAward_itsASign, L"itsASign", 0,0, Tile::bookshelf, (Achievement*) NULL) )->setAwardLocallyOnly()->postConstruct();
|
||||
Achievements::ironBelly = (new Achievement(eAward_ironBelly, L"ironBelly", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
Achievements::haveAShearfulDay = (new Achievement(eAward_haveAShearfulDay, L"haveAShearfulDay", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
Achievements::rainbowCollection = (new Achievement(eAward_rainbowCollection, L"rainbowCollection", 0,0, Tile::bookshelf, (Achievement*) NULL) )->setAwardLocallyOnly()->postConstruct();
|
||||
Achievements::stayinFrosty = (new Achievement(eAward_stayinFrosty, L"stayingFrosty", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
Achievements::chestfulOfCobblestone = (new Achievement(eAward_chestfulOfCobblestone, L"chestfulOfCobblestone", 0,0, Tile::bookshelf, (Achievement*) NULL) )->setAwardLocallyOnly()->postConstruct();
|
||||
Achievements::renewableEnergy = (new Achievement(eAward_renewableEnergy, L"renewableEnergy", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
Achievements::musicToMyEars = (new Achievement(eAward_musicToMyEars, L"musicToMyEars", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
Achievements::bodyGuard = (new Achievement(eAward_bodyGuard, L"bodyGuard", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
Achievements::ironMan = (new Achievement(eAward_ironMan, L"ironMan", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
Achievements::zombieDoctor = (new Achievement(eAward_zombieDoctor, L"zombieDoctor", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
Achievements::lionTamer = (new Achievement(eAward_lionTamer, L"lionTamer", 0,0, Tile::bookshelf, (Achievement*) NULL) )->postConstruct();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// Static { System.out.println(achievements.size() + " achievements"); } TODO
|
||||
|
||||
|
||||
void Achievements::init()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
|
||||
class Achievement;
|
||||
|
||||
class Achievements
|
||||
{
|
||||
friend class Achievement;
|
||||
|
||||
protected:
|
||||
static const int ACHIEVEMENT_OFFSET;
|
||||
|
||||
// maximum position of achievements (min and max)
|
||||
public:
|
||||
static const int ACHIEVEMENT_WIDTH_POSITION = 12;
|
||||
static const int ACHIEVEMENT_HEIGHT_POSITION = 12;
|
||||
|
||||
static int xMin, yMin, xMax, yMax;
|
||||
|
||||
static vector<Achievement *> *achievements;
|
||||
|
||||
static Achievement *openInventory;
|
||||
static Achievement *mineWood;
|
||||
static Achievement *buildWorkbench;
|
||||
static Achievement *buildPickaxe;
|
||||
static Achievement *buildFurnace;
|
||||
static Achievement *acquireIron;
|
||||
static Achievement *buildHoe;
|
||||
static Achievement *makeBread;
|
||||
static Achievement *bakeCake;
|
||||
static Achievement *buildBetterPickaxe;
|
||||
static Achievement *cookFish;
|
||||
static Achievement *onARail;
|
||||
static Achievement *buildSword;
|
||||
static Achievement *killEnemy;
|
||||
static Achievement *killCow;
|
||||
static Achievement *flyPig;
|
||||
|
||||
// 4J-JEV: Present on the PS3.
|
||||
static Achievement *snipeSkeleton;
|
||||
static Achievement *diamonds;
|
||||
//static Achievement *portal; //4J-JEV: Whats this?
|
||||
static Achievement *ghast;
|
||||
static Achievement *blazeRod;
|
||||
static Achievement *potion;
|
||||
static Achievement *theEnd;
|
||||
static Achievement *winGame;
|
||||
static Achievement *enchantments;
|
||||
|
||||
// 4J : WESTY : Added new acheivements.
|
||||
static Achievement *leaderOfThePack;
|
||||
static Achievement *MOARTools;
|
||||
static Achievement *dispenseWithThis;
|
||||
static Achievement *InToTheNether;
|
||||
|
||||
// 4J : WESTY : Added other awards.
|
||||
static Achievement *socialPost;
|
||||
static Achievement *eatPorkChop;
|
||||
static Achievement *play100Days;
|
||||
static Achievement *arrowKillCreeper;
|
||||
static Achievement *mine100Blocks;
|
||||
static Achievement *kill10Creepers;
|
||||
|
||||
#ifdef _EXTENDED_ACHIEVEMENTS
|
||||
static Achievement *overkill; // Old achievements;
|
||||
static Achievement *bookcase; // Old achievements;
|
||||
static Achievement *adventuringTime;
|
||||
static Achievement *repopulation;
|
||||
static Achievement *diamondsToYou;
|
||||
static Achievement *passingTheTime;
|
||||
static Achievement *archer;
|
||||
static Achievement *theHaggler;
|
||||
static Achievement *potPlanter;
|
||||
static Achievement *itsASign;
|
||||
static Achievement *ironBelly;
|
||||
static Achievement *haveAShearfulDay;
|
||||
static Achievement *rainbowCollection;
|
||||
static Achievement *stayinFrosty;
|
||||
static Achievement *chestfulOfCobblestone;
|
||||
static Achievement *renewableEnergy;
|
||||
static Achievement *musicToMyEars;
|
||||
static Achievement *bodyGuard;
|
||||
static Achievement *ironMan;
|
||||
static Achievement *zombieDoctor;
|
||||
static Achievement *lionTamer;
|
||||
#endif
|
||||
|
||||
static void staticCtor();
|
||||
|
||||
static void init();
|
||||
};
|
||||
@@ -0,0 +1,111 @@
|
||||
#include "stdafx.h"
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include "InputOutputStream.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "PacketListener.h"
|
||||
#include "AddEntityPacket.h"
|
||||
|
||||
|
||||
|
||||
void AddEntityPacket::_init(shared_ptr<Entity> e, int type, int data, int xp, int yp, int zp, int yRotp, int xRotp)
|
||||
{
|
||||
id = e->entityId;
|
||||
// 4J Stu - We should add entities at their "last sent" position so that the relative update packets
|
||||
// put them in the correct place
|
||||
x = xp;//(int) floor(e->x * 32);
|
||||
y = yp;//(int) floor(e->y * 32);
|
||||
z = zp;//(int) floor(e->z * 32);
|
||||
yRot = yRotp;
|
||||
xRot = xRotp;
|
||||
this->type = type;
|
||||
this->data = data;
|
||||
if (data > -1) // 4J - changed "no data" value to be -1, we can have a valid entity id of 0
|
||||
{
|
||||
double xd = e->xd;
|
||||
double yd = e->yd;
|
||||
double zd = e->zd;
|
||||
double m = 3.9;
|
||||
if (xd < -m) xd = -m;
|
||||
if (yd < -m) yd = -m;
|
||||
if (zd < -m) zd = -m;
|
||||
if (xd > m) xd = m;
|
||||
if (yd > m) yd = m;
|
||||
if (zd > m) zd = m;
|
||||
xa = (int) (xd * 8000.0);
|
||||
ya = (int) (yd * 8000.0);
|
||||
za = (int) (zd * 8000.0);
|
||||
}
|
||||
}
|
||||
|
||||
AddEntityPacket::AddEntityPacket()
|
||||
{
|
||||
}
|
||||
|
||||
AddEntityPacket::AddEntityPacket(shared_ptr<Entity> e, int type, int yRotp, int xRotp, int xp, int yp, int zp )
|
||||
{
|
||||
_init(e, type, -1, xp, yp, zp, yRotp, xRotp); // 4J - changed "no data" value to be -1, we can have a valid entity id of 0
|
||||
}
|
||||
|
||||
AddEntityPacket::AddEntityPacket(shared_ptr<Entity> e, int type, int data, int yRotp, int xRotp, int xp, int yp, int zp )
|
||||
{
|
||||
_init(e, type, data, xp, yp, zp, yRotp, xRotp);
|
||||
}
|
||||
|
||||
void AddEntityPacket::read(DataInputStream *dis) // throws IOException TODO 4J JEV add throws statement
|
||||
{
|
||||
id = dis->readShort();
|
||||
type = dis->readByte();
|
||||
#ifdef _LARGE_WORLDS
|
||||
x = dis->readInt();
|
||||
y = dis->readInt();
|
||||
z = dis->readInt();
|
||||
#else
|
||||
x = dis->readShort();
|
||||
y = dis->readShort();
|
||||
z = dis->readShort();
|
||||
#endif
|
||||
yRot = dis->readByte();
|
||||
xRot = dis->readByte();
|
||||
data = dis->readInt();
|
||||
if (data > -1) // 4J - changed "no data" value to be -1, we can have a valid entity id of 0
|
||||
{
|
||||
xa = dis->readShort();
|
||||
ya = dis->readShort();
|
||||
za = dis->readShort();
|
||||
}
|
||||
}
|
||||
|
||||
void AddEntityPacket::write(DataOutputStream *dos) // throws IOException TODO 4J JEV add throws statement
|
||||
{
|
||||
dos->writeShort(id);
|
||||
dos->writeByte(type);
|
||||
#ifdef _LARGE_WORLDS
|
||||
dos->writeInt(x);
|
||||
dos->writeInt(y);
|
||||
dos->writeInt(z);
|
||||
#else
|
||||
dos->writeShort(x);
|
||||
dos->writeShort(y);
|
||||
dos->writeShort(z);
|
||||
#endif
|
||||
dos->writeByte(yRot);
|
||||
dos->writeByte(xRot);
|
||||
dos->writeInt(data);
|
||||
if (data > -1) // 4J - changed "no data" value to be -1, we can have a valid entity id of 0
|
||||
{
|
||||
dos->writeShort(xa);
|
||||
dos->writeShort(ya);
|
||||
dos->writeShort(za);
|
||||
}
|
||||
}
|
||||
|
||||
void AddEntityPacket::handle(PacketListener *listener)
|
||||
{
|
||||
listener->handleAddEntity(shared_from_this());
|
||||
}
|
||||
|
||||
int AddEntityPacket::getEstimatedSize()
|
||||
{
|
||||
return 11 + data > -1 ? 6 : 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include "Packet.h"
|
||||
|
||||
class AddEntityPacket : public Packet, public enable_shared_from_this<AddEntityPacket>
|
||||
{
|
||||
public:
|
||||
static const int BOAT = 1;
|
||||
static const int ITEM = 2;
|
||||
static const int MINECART_RIDEABLE = 10;
|
||||
static const int MINECART_CHEST = 11;
|
||||
static const int MINECART_FURNACE = 12;
|
||||
static const int PRIMED_TNT = 50;
|
||||
static const int ENDER_CRYSTAL = 51;
|
||||
static const int ARROW = 60;
|
||||
static const int SNOWBALL = 61;
|
||||
static const int EGG = 62;
|
||||
static const int FIREBALL = 63;
|
||||
static const int SMALL_FIREBALL = 64;
|
||||
static const int THROWN_ENDERPEARL = 65;
|
||||
|
||||
static const int FALLING = 70;
|
||||
static const int ITEM_FRAME = 71;
|
||||
static const int EYEOFENDERSIGNAL = 72;
|
||||
static const int THROWN_POTION = 73;
|
||||
static const int FALLING_EGG = 74;
|
||||
static const int THROWN_EXPBOTTLE = 75;
|
||||
|
||||
static const int FISH_HOOK = 90;
|
||||
|
||||
// 4J Added TU9
|
||||
static const int DRAGON_FIRE_BALL = 200;
|
||||
|
||||
int id;
|
||||
int x, y, z;
|
||||
int xa, ya, za;
|
||||
int type;
|
||||
int data;
|
||||
byte yRot,xRot; // 4J added
|
||||
|
||||
private:
|
||||
void _init(shared_ptr<Entity> e, int type, int data, int xp, int yp, int zp, int yRotp, int xRotp );
|
||||
|
||||
public:
|
||||
AddEntityPacket();
|
||||
AddEntityPacket(shared_ptr<Entity> e, int type, int yRotp, int xRotp, int xp, int yp, int zp);
|
||||
AddEntityPacket(shared_ptr<Entity> e, int type, int data, int yRotp, int xRotp, int xp, int yp, int zp );
|
||||
|
||||
virtual void read(DataInputStream *dis);
|
||||
virtual void write(DataOutputStream *dos);
|
||||
virtual void handle(PacketListener *listener);
|
||||
virtual int getEstimatedSize();
|
||||
|
||||
public:
|
||||
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AddEntityPacket()); }
|
||||
virtual int getId() { return 23; }
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "InputOutputStream.h"
|
||||
#include "PacketListener.h"
|
||||
#include "AddExperienceOrbPacket.h"
|
||||
|
||||
|
||||
|
||||
AddExperienceOrbPacket::AddExperienceOrbPacket()
|
||||
{
|
||||
id = 0;
|
||||
x = y = z = 0;
|
||||
value = 0;
|
||||
}
|
||||
|
||||
AddExperienceOrbPacket::AddExperienceOrbPacket(shared_ptr<ExperienceOrb> e)
|
||||
{
|
||||
id = e->entityId;
|
||||
x = Mth::floor(e->x * 32);
|
||||
y = Mth::floor(e->y * 32);
|
||||
z = Mth::floor(e->z * 32);
|
||||
value = e->getValue();
|
||||
}
|
||||
|
||||
void AddExperienceOrbPacket::read(DataInputStream *dis)
|
||||
{
|
||||
id = dis->readInt();
|
||||
x = dis->readInt();
|
||||
y = dis->readInt();
|
||||
z = dis->readInt();
|
||||
value = dis->readShort();
|
||||
}
|
||||
|
||||
void AddExperienceOrbPacket::write(DataOutputStream *dos)
|
||||
{
|
||||
dos->writeInt(id);
|
||||
dos->writeInt(x);
|
||||
dos->writeInt(y);
|
||||
dos->writeInt(z);
|
||||
dos->writeShort(value);
|
||||
}
|
||||
|
||||
void AddExperienceOrbPacket::handle(PacketListener *listener)
|
||||
{
|
||||
listener->handleAddExperienceOrb(shared_from_this());
|
||||
}
|
||||
|
||||
int AddExperienceOrbPacket::getEstimatedSize()
|
||||
{
|
||||
return 18;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "Packet.h"
|
||||
|
||||
class ExperienceOrb;
|
||||
|
||||
class AddExperienceOrbPacket : public Packet, public enable_shared_from_this<AddExperienceOrbPacket>
|
||||
{
|
||||
public:
|
||||
int id;
|
||||
int x, y, z;
|
||||
int value;
|
||||
|
||||
AddExperienceOrbPacket();
|
||||
AddExperienceOrbPacket(shared_ptr<ExperienceOrb> e);
|
||||
|
||||
virtual void read(DataInputStream *dis);
|
||||
virtual void write(DataOutputStream *dos);
|
||||
virtual void handle(PacketListener *listener);
|
||||
virtual int getEstimatedSize();
|
||||
|
||||
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AddExperienceOrbPacket()); }
|
||||
virtual int getId() { return 26; }
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "stdafx.h"
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include "InputOutputStream.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "net.minecraft.world.entity.global.h"
|
||||
#include "PacketListener.h"
|
||||
#include "AddGlobalEntityPacket.h"
|
||||
|
||||
|
||||
|
||||
const int AddGlobalEntityPacket::LIGHTNING = 1;
|
||||
|
||||
AddGlobalEntityPacket::AddGlobalEntityPacket()
|
||||
{
|
||||
id = -1;
|
||||
x = 0;
|
||||
y = 0;
|
||||
x = 0;
|
||||
type = 0;
|
||||
}
|
||||
|
||||
AddGlobalEntityPacket::AddGlobalEntityPacket(shared_ptr<Entity> e)
|
||||
{
|
||||
id = e->entityId;
|
||||
x = Mth::floor(e->x * 32);
|
||||
y = Mth::floor(e->y * 32);
|
||||
z = Mth::floor(e->z * 32);
|
||||
if (dynamic_pointer_cast<LightningBolt>(e) != NULL)
|
||||
{
|
||||
this->type = LIGHTNING;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->type = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AddGlobalEntityPacket::read(DataInputStream *dis) // throws IOException
|
||||
{
|
||||
id = dis->readInt();
|
||||
type = dis->readByte();
|
||||
x = dis->readInt();
|
||||
y = dis->readInt();
|
||||
z = dis->readInt();
|
||||
}
|
||||
|
||||
void AddGlobalEntityPacket::write(DataOutputStream *dos) // throws IOException
|
||||
{
|
||||
dos->writeInt(id);
|
||||
dos->writeByte(type);
|
||||
dos->writeInt(x);
|
||||
dos->writeInt(y);
|
||||
dos->writeInt(z);
|
||||
}
|
||||
|
||||
void AddGlobalEntityPacket::handle(PacketListener *listener)
|
||||
{
|
||||
listener->handleAddGlobalEntity(shared_from_this());
|
||||
}
|
||||
|
||||
int AddGlobalEntityPacket::getEstimatedSize()
|
||||
{
|
||||
return 17;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "Packet.h"
|
||||
|
||||
class AddGlobalEntityPacket : public Packet, public enable_shared_from_this<AddGlobalEntityPacket>
|
||||
{
|
||||
public:
|
||||
static const int LIGHTNING;
|
||||
|
||||
int id;
|
||||
int x, y, z;
|
||||
int type;
|
||||
|
||||
AddGlobalEntityPacket();
|
||||
AddGlobalEntityPacket(shared_ptr<Entity> e);
|
||||
|
||||
virtual void read(DataInputStream *dis);
|
||||
virtual void write(DataOutputStream *dos);
|
||||
virtual void handle(PacketListener *listener);
|
||||
virtual int getEstimatedSize();
|
||||
|
||||
public:
|
||||
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AddGlobalEntityPacket()); }
|
||||
virtual int getId() { return 71; }
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.newbiome.layer.h"
|
||||
#include "net.minecraft.world.level.biome.h"
|
||||
|
||||
AddIslandLayer::AddIslandLayer(__int64 seedMixup, shared_ptr<Layer>parent) : Layer(seedMixup)
|
||||
{
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
intArray AddIslandLayer::getArea(int xo, int yo, int w, int h)
|
||||
{
|
||||
int px = xo - 1;
|
||||
int py = yo - 1;
|
||||
int pw = w + 2;
|
||||
int ph = h + 2;
|
||||
intArray p = parent->getArea(px, py, pw, ph);
|
||||
|
||||
intArray result = IntCache::allocate(w * h);
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
int n1 = p[(x + 0) + (y + 0) * pw];
|
||||
int n2 = p[(x + 2) + (y + 0) * pw];
|
||||
int n3 = p[(x + 0) + (y + 2) * pw];
|
||||
int n4 = p[(x + 2) + (y + 2) * pw];
|
||||
int c = p[(x + 1) + (y + 1) * pw];
|
||||
initRandom(x + xo, y + yo);
|
||||
if (c == 0 && (n1 != 0 || n2 != 0 || n3 != 0 || n4 != 0))
|
||||
{
|
||||
int odds = 1;
|
||||
int swap = 1;
|
||||
if (n1 != 0 && nextRandom(odds++) == 0) swap = n1;
|
||||
if (n2 != 0 && nextRandom(odds++) == 0) swap = n2;
|
||||
if (n3 != 0 && nextRandom(odds++) == 0) swap = n3;
|
||||
if (n4 != 0 && nextRandom(odds++) == 0) swap = n4;
|
||||
if (nextRandom(3) == 0)
|
||||
{
|
||||
result[x + y * w] = swap;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (swap == Biome::iceFlats->id) result[x + y * w] = Biome::frozenOcean->id;
|
||||
else result[x + y * w] = 0;
|
||||
}
|
||||
}
|
||||
else if (c > 0 && (n1 == 0 || n2 == 0 || n3 == 0 || n4 == 0))
|
||||
{
|
||||
if (nextRandom(5) == 0)
|
||||
{
|
||||
if (c == Biome::iceFlats->id) result[x + y * w] = Biome::frozenOcean->id;
|
||||
else result[x + y * w] = 0;
|
||||
}
|
||||
else result[x + y * w] = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
result[x + y * w] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "Layer.h"
|
||||
|
||||
class AddIslandLayer : public Layer
|
||||
{
|
||||
public:
|
||||
AddIslandLayer(__int64 seedMixup, shared_ptr<Layer>parent);
|
||||
|
||||
intArray getArea(int xo, int yo, int w, int h);
|
||||
};
|
||||
@@ -0,0 +1,140 @@
|
||||
#include "stdafx.h"
|
||||
#include <iostream>
|
||||
#include "InputOutputStream.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "PacketListener.h"
|
||||
#include "AddMobPacket.h"
|
||||
|
||||
|
||||
|
||||
AddMobPacket::AddMobPacket()
|
||||
{
|
||||
id = -1;
|
||||
type = 0;
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
yRot = 0;
|
||||
xRot = 0;
|
||||
entityData = nullptr;
|
||||
unpack = NULL;
|
||||
}
|
||||
|
||||
AddMobPacket::~AddMobPacket()
|
||||
{
|
||||
delete unpack;
|
||||
}
|
||||
|
||||
AddMobPacket::AddMobPacket(shared_ptr<Mob> mob, int yRotp, int xRotp, int xp, int yp, int zp, int yHeadRotp)
|
||||
{
|
||||
id = mob->entityId;
|
||||
|
||||
type = (byte) EntityIO::getId(mob);
|
||||
// 4J Stu - We should add entities at their "last sent" position so that the relative update packets
|
||||
// put them in the correct place
|
||||
x = xp;//Mth::floor(mob->x * 32);
|
||||
y = yp;//Mth::floor(mob->y * 32);
|
||||
z = zp;//Mth::floor(mob->z * 32);
|
||||
// 4J - changed - send current "previously sent" value of rotations to put this in sync with other clients
|
||||
yRot = yRotp;
|
||||
xRot = xRotp;
|
||||
yHeadRot = yHeadRotp;
|
||||
// yRot = (byte) (mob->yRot * 256 / 360);
|
||||
// xRot = (byte) (mob->xRot * 256 / 360);
|
||||
// yHeadRot = (byte) (mob->yHeadRot * 256 / 360);
|
||||
|
||||
// From SetEntityMotionpacket
|
||||
double m = 3.9;
|
||||
double xd = mob->xd;
|
||||
double yd = mob->yd;
|
||||
double zd = mob->zd;
|
||||
if (xd < -m) xd = -m;
|
||||
if (yd < -m) yd = -m;
|
||||
if (zd < -m) zd = -m;
|
||||
if (xd > m) xd = m;
|
||||
if (yd > m) yd = m;
|
||||
if (zd > m) zd = m;
|
||||
this->xd = (int) (xd * 8000.0);
|
||||
this->yd = (int) (yd * 8000.0);
|
||||
this->zd = (int) (zd * 8000.0);
|
||||
|
||||
// printf("%d: New add mob rot %d\n",id,yRot);
|
||||
|
||||
entityData = mob->getEntityData();
|
||||
unpack = NULL;
|
||||
}
|
||||
|
||||
void AddMobPacket::read(DataInputStream *dis) //throws IOException
|
||||
{
|
||||
id = dis->readShort();
|
||||
type = dis->readByte() & 0xff;
|
||||
#ifdef _LARGE_WORLDS
|
||||
x = dis->readInt();
|
||||
y = dis->readInt();
|
||||
z = dis->readInt();
|
||||
#else
|
||||
x = dis->readShort();
|
||||
y = dis->readShort();
|
||||
z = dis->readShort();
|
||||
#endif
|
||||
yRot = dis->readByte();
|
||||
xRot = dis->readByte();
|
||||
yHeadRot = dis->readByte();
|
||||
xd = dis->readShort();
|
||||
yd = dis->readShort();
|
||||
zd = dis->readShort();
|
||||
MemSect(1);
|
||||
unpack = SynchedEntityData::unpack(dis);
|
||||
MemSect(0);
|
||||
}
|
||||
|
||||
void AddMobPacket::write(DataOutputStream *dos) //throws IOException
|
||||
{
|
||||
dos->writeShort(id);
|
||||
dos->writeByte(type & 0xff);
|
||||
#ifdef _LARGE_WORLDS
|
||||
dos->writeInt(x);
|
||||
dos->writeInt(y);
|
||||
dos->writeInt(z);
|
||||
#else
|
||||
dos->writeShort(x);
|
||||
dos->writeShort(y);
|
||||
dos->writeShort(z);
|
||||
#endif
|
||||
dos->writeByte(yRot);
|
||||
dos->writeByte(xRot);
|
||||
dos->writeByte(yHeadRot);
|
||||
dos->writeShort(xd);
|
||||
dos->writeShort(yd);
|
||||
dos->writeShort(zd);
|
||||
entityData->packAll(dos);
|
||||
}
|
||||
|
||||
void AddMobPacket::handle(PacketListener *listener)
|
||||
{
|
||||
listener->handleAddMob(shared_from_this());
|
||||
}
|
||||
|
||||
int AddMobPacket::getEstimatedSize()
|
||||
{
|
||||
int size = 11;
|
||||
if( entityData != NULL )
|
||||
{
|
||||
size += entityData->getSizeInBytes();
|
||||
}
|
||||
else if( unpack != NULL )
|
||||
{
|
||||
// 4J Stu - This is an incoming value which we aren't currently analysing
|
||||
//size += unpack->get
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
vector<shared_ptr<SynchedEntityData::DataItem> > *AddMobPacket::getUnpackedData()
|
||||
{
|
||||
if (unpack == NULL)
|
||||
{
|
||||
unpack = entityData->getAll();
|
||||
}
|
||||
return unpack;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include "Packet.h"
|
||||
#include "SynchedEntityData.h"
|
||||
|
||||
class Mob;
|
||||
|
||||
class AddMobPacket : public Packet, public enable_shared_from_this<AddMobPacket>
|
||||
{
|
||||
public:
|
||||
int id;
|
||||
int type;
|
||||
int x, y, z;
|
||||
int xd, yd, zd;
|
||||
byte yRot, xRot, yHeadRot;
|
||||
|
||||
private:
|
||||
shared_ptr<SynchedEntityData> entityData;
|
||||
vector<shared_ptr<SynchedEntityData::DataItem> > *unpack;
|
||||
|
||||
public:
|
||||
AddMobPacket();
|
||||
~AddMobPacket();
|
||||
AddMobPacket(shared_ptr<Mob> mob, int yRotp, int xRotp, int xp, int yp, int zp, int yHeadRotp);
|
||||
|
||||
virtual void read(DataInputStream *dis);
|
||||
virtual void write(DataOutputStream *dos);
|
||||
virtual void handle(PacketListener *listener);
|
||||
virtual int getEstimatedSize();
|
||||
|
||||
vector<shared_ptr<SynchedEntityData::DataItem> > *getUnpackedData();
|
||||
|
||||
public:
|
||||
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AddMobPacket()); }
|
||||
virtual int getId() { return 24; }
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.newbiome.layer.h"
|
||||
#include "net.minecraft.world.level.biome.h"
|
||||
|
||||
|
||||
AddMushroomIslandLayer::AddMushroomIslandLayer(__int64 seedMixup, shared_ptr<Layer> parent) : Layer(seedMixup)
|
||||
{
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
intArray AddMushroomIslandLayer::getArea(int xo, int yo, int w, int h)
|
||||
{
|
||||
int px = xo - 1;
|
||||
int py = yo - 1;
|
||||
int pw = w + 2;
|
||||
int ph = h + 2;
|
||||
intArray p = parent->getArea(px, py, pw, ph);
|
||||
|
||||
intArray result = IntCache::allocate(w * h);
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
int n1 = p[(x + 0) + (y + 0) * pw];
|
||||
int n2 = p[(x + 2) + (y + 0) * pw];
|
||||
int n3 = p[(x + 0) + (y + 2) * pw];
|
||||
int n4 = p[(x + 2) + (y + 2) * pw];
|
||||
int c = p[(x + 1) + (y + 1) * pw];
|
||||
initRandom(x + xo, y + yo);
|
||||
if (c == 0 && (n1 == 0 && n2 == 0 && n3 == 0 && n4 == 0) && nextRandom(100) == 0)
|
||||
{
|
||||
result[x + y * w] = Biome::mushroomIsland->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
result[x + y * w] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "Layer.h"
|
||||
|
||||
class AddMushroomIslandLayer : public Layer
|
||||
{
|
||||
public:
|
||||
AddMushroomIslandLayer(__int64 seedMixup, shared_ptr<Layer> parent);
|
||||
virtual intArray getArea(int xo, int yo, int w, int h);
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "stdafx.h"
|
||||
#include <iostream>
|
||||
#include "InputOutputStream.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "PacketListener.h"
|
||||
#include "AddPaintingPacket.h"
|
||||
|
||||
|
||||
|
||||
AddPaintingPacket::AddPaintingPacket()
|
||||
{
|
||||
id = -1;
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
dir = 0;
|
||||
motive = L"";
|
||||
}
|
||||
|
||||
AddPaintingPacket::AddPaintingPacket(shared_ptr<Painting> e)
|
||||
{
|
||||
id = e->entityId;
|
||||
x = e->xTile;
|
||||
y = e->yTile;
|
||||
z = e->zTile;
|
||||
dir = e->dir;
|
||||
motive = e->motive->name;
|
||||
}
|
||||
|
||||
void AddPaintingPacket::read(DataInputStream *dis) //throws IOException
|
||||
{
|
||||
id = dis->readInt();
|
||||
motive = readUtf(dis, Painting::Motive::MAX_MOTIVE_NAME_LENGTH);
|
||||
x = dis->readInt();
|
||||
y = dis->readInt();
|
||||
z = dis->readInt();
|
||||
dir = dis->readInt();
|
||||
}
|
||||
|
||||
void AddPaintingPacket::write(DataOutputStream *dos) //throws IOException
|
||||
{
|
||||
dos->writeInt(id);
|
||||
writeUtf(motive, dos);
|
||||
dos->writeInt(x);
|
||||
dos->writeInt(y);
|
||||
dos->writeInt(z);
|
||||
dos->writeInt(dir);
|
||||
}
|
||||
|
||||
void AddPaintingPacket::handle(PacketListener *listener)
|
||||
{
|
||||
listener->handleAddPainting(shared_from_this());
|
||||
}
|
||||
|
||||
int AddPaintingPacket::getEstimatedSize()
|
||||
{
|
||||
return 24;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include "Packet.h"
|
||||
|
||||
class Painting;
|
||||
|
||||
class AddPaintingPacket : public Packet, public enable_shared_from_this<AddPaintingPacket>
|
||||
{
|
||||
public:
|
||||
int id;
|
||||
int x, y, z;
|
||||
int dir;
|
||||
wstring motive;
|
||||
|
||||
public:
|
||||
AddPaintingPacket();
|
||||
AddPaintingPacket(shared_ptr<Painting> e);
|
||||
|
||||
virtual void read(DataInputStream *dis);
|
||||
virtual void write(DataOutputStream *dos);
|
||||
virtual void handle(PacketListener *listener);
|
||||
virtual int getEstimatedSize();
|
||||
public:
|
||||
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AddPaintingPacket()); }
|
||||
virtual int getId() { return 25; }
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
#include "stdafx.h"
|
||||
#include <iostream>
|
||||
#include "InputOutputStream.h"
|
||||
#include "net.minecraft.world.entity.player.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "PacketListener.h"
|
||||
#include "AddPlayerPacket.h"
|
||||
|
||||
|
||||
|
||||
AddPlayerPacket::AddPlayerPacket()
|
||||
{
|
||||
id = -1;
|
||||
name = L"";
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
yRot = 0;
|
||||
xRot = 0;
|
||||
carriedItem = 0;
|
||||
xuid = INVALID_XUID;
|
||||
m_playerIndex = 0;
|
||||
m_skinId = 0;
|
||||
m_capeId = 0;
|
||||
m_uiGamePrivileges = 0;
|
||||
entityData = nullptr;
|
||||
unpack = NULL;
|
||||
}
|
||||
|
||||
AddPlayerPacket::~AddPlayerPacket()
|
||||
{
|
||||
if(unpack != NULL) delete unpack;
|
||||
}
|
||||
|
||||
AddPlayerPacket::AddPlayerPacket(shared_ptr<Player> player, PlayerUID xuid, PlayerUID OnlineXuid,int xp, int yp, int zp, int yRotp, int xRotp, int yHeadRotp)
|
||||
{
|
||||
id = player->entityId;
|
||||
name = player->name;
|
||||
|
||||
// 4J Stu - Send "previously sent" value of position as well so that we stay in sync
|
||||
x = xp;//Mth::floor(player->x * 32);
|
||||
y = yp;//Mth::floor(player->y * 32);
|
||||
z = zp;//Mth::floor(player->z * 32);
|
||||
// 4J - changed - send current "previously sent" value of rotations to put this in sync with other clients
|
||||
yRot = yRotp;
|
||||
xRot = xRotp;
|
||||
yHeadRot = yHeadRotp; // 4J Added
|
||||
// yRot = (byte) (player->yRot * 256 / 360);
|
||||
// xRot = (byte) (player->xRot * 256 / 360);
|
||||
|
||||
//printf("%d: New add player (%f,%f,%f) : (%d,%d,%d) : xRot %d, yRot %d\n",id,player->x,player->y,player->z,x,y,z,xRot,yRot);
|
||||
|
||||
shared_ptr<ItemInstance> itemInstance = player->inventory->getSelected();
|
||||
carriedItem = itemInstance == NULL ? 0 : itemInstance->id;
|
||||
|
||||
this->xuid = xuid;
|
||||
this->OnlineXuid = OnlineXuid;
|
||||
m_playerIndex = (BYTE)player->getPlayerIndex();
|
||||
m_skinId = player->getCustomSkin();
|
||||
m_capeId = player->getCustomCape();
|
||||
m_uiGamePrivileges = player->getAllPlayerGamePrivileges();
|
||||
|
||||
entityData = player->getEntityData();
|
||||
unpack = NULL;
|
||||
}
|
||||
|
||||
void AddPlayerPacket::read(DataInputStream *dis) //throws IOException
|
||||
{
|
||||
id = dis->readInt();
|
||||
name = readUtf(dis, Player::MAX_NAME_LENGTH);
|
||||
x = dis->readInt();
|
||||
y = dis->readInt();
|
||||
z = dis->readInt();
|
||||
yRot = dis->readByte();
|
||||
xRot = dis->readByte();
|
||||
yHeadRot = dis->readByte(); // 4J Added
|
||||
carriedItem = dis->readShort();
|
||||
xuid = dis->readPlayerUID();
|
||||
OnlineXuid = dis->readPlayerUID();
|
||||
m_playerIndex = dis->readByte();
|
||||
INT skinId = dis->readInt();
|
||||
m_skinId = *(DWORD *)&skinId;
|
||||
INT capeId = dis->readInt();
|
||||
m_capeId = *(DWORD *)&capeId;
|
||||
INT privileges = dis->readInt();
|
||||
m_uiGamePrivileges = *(unsigned int *)&privileges;
|
||||
MemSect(1);
|
||||
unpack = SynchedEntityData::unpack(dis);
|
||||
MemSect(0);
|
||||
}
|
||||
|
||||
void AddPlayerPacket::write(DataOutputStream *dos) //throws IOException
|
||||
{
|
||||
dos->writeInt(id);
|
||||
writeUtf(name, dos);
|
||||
dos->writeInt(x);
|
||||
dos->writeInt(y);
|
||||
dos->writeInt(z);
|
||||
dos->writeByte(yRot);
|
||||
dos->writeByte(xRot);
|
||||
dos->writeByte(yHeadRot); // 4J Added
|
||||
dos->writeShort(carriedItem);
|
||||
dos->writePlayerUID(xuid);
|
||||
dos->writePlayerUID(OnlineXuid);
|
||||
dos->writeByte(m_playerIndex);
|
||||
dos->writeInt(m_skinId);
|
||||
dos->writeInt(m_capeId);
|
||||
dos->writeInt(m_uiGamePrivileges);
|
||||
entityData->packAll(dos);
|
||||
|
||||
}
|
||||
|
||||
void AddPlayerPacket::handle(PacketListener *listener)
|
||||
{
|
||||
listener->handleAddPlayer(shared_from_this());
|
||||
}
|
||||
|
||||
int AddPlayerPacket::getEstimatedSize()
|
||||
{
|
||||
int iSize= sizeof(int) + Player::MAX_NAME_LENGTH + sizeof(int) + sizeof(int) + sizeof(int) + sizeof(BYTE) + sizeof(BYTE) +sizeof(short) + sizeof(PlayerUID) + sizeof(PlayerUID) + sizeof(int) + sizeof(BYTE) + sizeof(unsigned int) + sizeof(byte);
|
||||
|
||||
if( entityData != NULL )
|
||||
{
|
||||
iSize += entityData->getSizeInBytes();
|
||||
}
|
||||
else if( unpack != NULL )
|
||||
{
|
||||
// 4J Stu - This is an incoming value which we aren't currently analysing
|
||||
//iSize += unpack->get
|
||||
}
|
||||
|
||||
return iSize;
|
||||
}
|
||||
|
||||
vector<shared_ptr<SynchedEntityData::DataItem> > *AddPlayerPacket::getUnpackedData()
|
||||
{
|
||||
if (unpack == NULL)
|
||||
{
|
||||
unpack = entityData->getAll();
|
||||
}
|
||||
return unpack;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include "Packet.h"
|
||||
#include "SynchedEntityData.h"
|
||||
|
||||
class Player;
|
||||
|
||||
class AddPlayerPacket : public Packet, public enable_shared_from_this<AddPlayerPacket>
|
||||
{
|
||||
|
||||
private:
|
||||
shared_ptr<SynchedEntityData> entityData;
|
||||
vector<shared_ptr<SynchedEntityData::DataItem> > *unpack;
|
||||
|
||||
public:
|
||||
int id;
|
||||
wstring name;
|
||||
int x, y, z;
|
||||
char yRot, xRot;
|
||||
int carriedItem;
|
||||
PlayerUID xuid; // 4J Added
|
||||
PlayerUID OnlineXuid; // 4J Added
|
||||
BYTE m_playerIndex; // 4J Added
|
||||
DWORD m_skinId; // 4J Added
|
||||
DWORD m_capeId; // 4J Added
|
||||
unsigned int m_uiGamePrivileges; // 4J Added
|
||||
byte yHeadRot; // 4J Added
|
||||
|
||||
AddPlayerPacket();
|
||||
~AddPlayerPacket();
|
||||
AddPlayerPacket(shared_ptr<Player> player, PlayerUID xuid, PlayerUID OnlineXuid,int xp, int yp, int zp, int yRotp, int xRotp, int yHeadRotp);
|
||||
|
||||
virtual void read(DataInputStream *dis);
|
||||
virtual void write(DataOutputStream *dos);
|
||||
virtual void handle(PacketListener *listener);
|
||||
virtual int getEstimatedSize();
|
||||
|
||||
vector<shared_ptr<SynchedEntityData::DataItem> > *getUnpackedData();
|
||||
public:
|
||||
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AddPlayerPacket()); }
|
||||
virtual int getId() { return 20; }
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.newbiome.layer.h"
|
||||
#include "net.minecraft.world.level.biome.h"
|
||||
|
||||
AddSnowLayer::AddSnowLayer(__int64 seedMixup, shared_ptr<Layer> parent) : Layer(seedMixup)
|
||||
{
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
intArray AddSnowLayer::getArea(int xo, int yo, int w, int h)
|
||||
{
|
||||
int px = xo - 1;
|
||||
int py = yo - 1;
|
||||
int pw = w + 2;
|
||||
int ph = h + 2;
|
||||
intArray p = parent->getArea(px, py, pw, ph);
|
||||
|
||||
intArray result = IntCache::allocate(w * h);
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
int c = p[(x + 1) + (y + 1) * pw];
|
||||
initRandom(x + xo, y + yo);
|
||||
if (c == 0)
|
||||
{
|
||||
result[x + y * w] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int r = nextRandom(5);
|
||||
if (r == 0) r = Biome::iceFlats->id;
|
||||
else r = 1;
|
||||
result[x + y * w] = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "Layer.h"
|
||||
|
||||
class AddSnowLayer : public Layer
|
||||
{
|
||||
public:
|
||||
AddSnowLayer(__int64 seedMixup, shared_ptr<Layer> parent);
|
||||
virtual intArray getArea(int xo, int yo, int w, int h);
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "ChatPacket.h"
|
||||
|
||||
class CommandSender;
|
||||
|
||||
class AdminLogCommand
|
||||
{
|
||||
public:
|
||||
static const int LOGTYPE_DONT_SHOW_TO_SELF = 1;
|
||||
|
||||
virtual void logAdminCommand(shared_ptr<CommandSender> source, int type, ChatPacket::EChatPacketMessage messageType, const wstring& message = L"", int customData = -1, const wstring& additionalMessage = L"") = 0;
|
||||
};
|
||||
@@ -0,0 +1,131 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "net.minecraft.world.entity.player.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "SynchedEntityData.h"
|
||||
#include "GenericStats.h"
|
||||
#include "AgableMob.h"
|
||||
|
||||
AgableMob::AgableMob(Level *level) : PathfinderMob(level)
|
||||
{
|
||||
registeredBBWidth = -1;
|
||||
registeredBBHeight = 0;
|
||||
}
|
||||
|
||||
bool AgableMob::interact(shared_ptr<Player> player)
|
||||
{
|
||||
shared_ptr<ItemInstance> item = player->inventory->getSelected();
|
||||
|
||||
if (item != NULL && item->id == Item::monsterPlacer_Id)
|
||||
{
|
||||
if (!level->isClientSide)
|
||||
{
|
||||
eINSTANCEOF classToSpawn = EntityIO::getClass(item->getAuxValue());
|
||||
if (classToSpawn != eTYPE_NOTSET && (classToSpawn & eTYPE_AGABLE_MOB) == eTYPE_AGABLE_MOB && classToSpawn == GetType() ) // 4J Added GetType() check to only spawn same type
|
||||
{
|
||||
shared_ptr<AgableMob> offspring = getBreedOffspring(dynamic_pointer_cast<AgableMob>(shared_from_this()));
|
||||
if (offspring != NULL)
|
||||
{
|
||||
offspring->setAge(-20 * 60 * 20);
|
||||
offspring->moveTo(x, y, z, 0, 0);
|
||||
|
||||
level->addEntity(offspring);
|
||||
|
||||
if (!player->abilities.instabuild)
|
||||
{
|
||||
item->count--;
|
||||
|
||||
if (item->count <= 0)
|
||||
{
|
||||
player->inventory->setItem(player->inventory->selected, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PathfinderMob::interact(player);
|
||||
}
|
||||
|
||||
void AgableMob::defineSynchedData()
|
||||
{
|
||||
PathfinderMob::defineSynchedData();
|
||||
entityData->define(DATA_AGE_ID, 0);
|
||||
}
|
||||
|
||||
int AgableMob::getAge()
|
||||
{
|
||||
return entityData->getInteger(DATA_AGE_ID);
|
||||
}
|
||||
|
||||
void AgableMob::setAge(int age)
|
||||
{
|
||||
entityData->set(DATA_AGE_ID, age);
|
||||
updateSize(isBaby());
|
||||
}
|
||||
|
||||
void AgableMob::addAdditonalSaveData(CompoundTag *tag)
|
||||
{
|
||||
PathfinderMob::addAdditonalSaveData(tag);
|
||||
tag->putInt(L"Age", getAge());
|
||||
}
|
||||
|
||||
void AgableMob::readAdditionalSaveData(CompoundTag *tag)
|
||||
{
|
||||
PathfinderMob::readAdditionalSaveData(tag);
|
||||
setAge(tag->getInt(L"Age"));
|
||||
}
|
||||
|
||||
void AgableMob::aiStep()
|
||||
{
|
||||
PathfinderMob::aiStep();
|
||||
|
||||
if(level->isClientSide)
|
||||
{
|
||||
updateSize(isBaby());
|
||||
}
|
||||
else
|
||||
{
|
||||
int age = getAge();
|
||||
if (age < 0)
|
||||
{
|
||||
age++;
|
||||
setAge(age);
|
||||
}
|
||||
else if (age > 0)
|
||||
{
|
||||
age--;
|
||||
setAge(age);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AgableMob::isBaby()
|
||||
{
|
||||
return getAge() < 0;
|
||||
}
|
||||
|
||||
void AgableMob::updateSize(bool isBaby)
|
||||
{
|
||||
internalSetSize(isBaby ? .5f : 1.0f);
|
||||
}
|
||||
|
||||
void AgableMob::setSize(float w, float h)
|
||||
{
|
||||
bool inited = registeredBBWidth > 0;
|
||||
|
||||
registeredBBWidth = w;
|
||||
registeredBBHeight = h;
|
||||
|
||||
if (!inited)
|
||||
{
|
||||
internalSetSize(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void AgableMob::internalSetSize(float scale)
|
||||
{
|
||||
PathfinderMob::setSize(registeredBBWidth * scale, registeredBBHeight * scale);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "PathfinderMob.h"
|
||||
|
||||
class AgableMob : public PathfinderMob
|
||||
{
|
||||
private:
|
||||
static const int DATA_AGE_ID = 12;
|
||||
|
||||
float registeredBBWidth;
|
||||
float registeredBBHeight;
|
||||
|
||||
public:
|
||||
AgableMob(Level *level);
|
||||
|
||||
virtual bool interact(shared_ptr<Player> player);
|
||||
|
||||
protected:
|
||||
virtual void defineSynchedData();
|
||||
|
||||
public:
|
||||
virtual shared_ptr<AgableMob> getBreedOffspring(shared_ptr<AgableMob> target) = 0;
|
||||
virtual int getAge();
|
||||
virtual void setAge(int age);
|
||||
virtual void addAdditonalSaveData(CompoundTag *tag);
|
||||
virtual void readAdditionalSaveData(CompoundTag *tag);
|
||||
virtual void aiStep();
|
||||
virtual bool isBaby();
|
||||
virtual void updateSize(bool isBaby);
|
||||
|
||||
protected:
|
||||
virtual void setSize(float w, float h);
|
||||
void internalSetSize(float scale);
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "stdafx.h"
|
||||
#include "AirTile.h"
|
||||
|
||||
AirTile::AirTile(int id) : Tile(id, Material::air)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "Tile.h"
|
||||
#include "Material.h"
|
||||
|
||||
class AirTile : public Tile
|
||||
{
|
||||
friend class Tile;
|
||||
|
||||
protected:
|
||||
AirTile(int id);
|
||||
};
|
||||
@@ -0,0 +1,458 @@
|
||||
#include "stdafx.h"
|
||||
#include "com.mojang.nbt.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "net.minecraft.world.phys.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.level.storage.h"
|
||||
#include "net.minecraft.world.entity.player.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "net.minecraft.world.entity.projectile.h"
|
||||
#include "net.minecraft.world.damagesource.h"
|
||||
#include "Random.h"
|
||||
#include "Animal.h"
|
||||
|
||||
|
||||
|
||||
Animal::Animal(Level *level) : AgableMob( level )
|
||||
{
|
||||
// inLove = 0; // 4J removed - now synched data
|
||||
loveTime = 0;
|
||||
loveCause = shared_ptr<Player>();
|
||||
|
||||
setDespawnProtected();
|
||||
}
|
||||
|
||||
void Animal::defineSynchedData()
|
||||
{
|
||||
AgableMob::defineSynchedData();
|
||||
|
||||
entityData->define(DATA_IN_LOVE, (int)0); // 4J added
|
||||
}
|
||||
|
||||
void Animal::serverAiMobStep()
|
||||
{
|
||||
if (getAge() != 0) setInLoveValue(0);
|
||||
AgableMob::serverAiMobStep();
|
||||
}
|
||||
|
||||
|
||||
void Animal::aiStep()
|
||||
{
|
||||
AgableMob::aiStep();
|
||||
|
||||
if (getAge() != 0) setInLoveValue(0);
|
||||
|
||||
if (getInLoveValue() > 0)
|
||||
{
|
||||
setInLoveValue(getInLoveValue()-1);
|
||||
if (getInLoveValue() % 10 == 0)
|
||||
{
|
||||
double xa = random->nextGaussian() * 0.02;
|
||||
double ya = random->nextGaussian() * 0.02;
|
||||
double za = random->nextGaussian() * 0.02;
|
||||
level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
loveTime = 0;
|
||||
}
|
||||
|
||||
updateDespawnProtectedState(); // 4J added
|
||||
}
|
||||
|
||||
void Animal::checkHurtTarget(shared_ptr<Entity> target, float d)
|
||||
{
|
||||
if (dynamic_pointer_cast<Player>(target) != NULL)
|
||||
{
|
||||
if (d < 3)
|
||||
{
|
||||
double xd = target->x - x;
|
||||
double zd = target->z - z;
|
||||
yRot = (float) (atan2(zd, xd) * 180 / PI) - 90;
|
||||
|
||||
holdGround = true;
|
||||
}
|
||||
|
||||
shared_ptr<Player> p = dynamic_pointer_cast<Player>(target);
|
||||
if (p->getSelectedItem() != NULL && this->isFood(p->getSelectedItem()))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
attackTarget = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
else if (dynamic_pointer_cast<Animal>(target) != NULL)
|
||||
{
|
||||
shared_ptr<Animal> a = dynamic_pointer_cast<Animal>(target);
|
||||
if (getAge() > 0 && a->getAge() < 0)
|
||||
{
|
||||
if (d < 2.5)
|
||||
{
|
||||
holdGround = true;
|
||||
}
|
||||
}
|
||||
else if (getInLoveValue() > 0 && a->getInLoveValue() > 0)
|
||||
{
|
||||
if (a->attackTarget == NULL) a->attackTarget = shared_from_this();
|
||||
|
||||
if (a->attackTarget == shared_from_this() && d < 3.5)
|
||||
{
|
||||
a->setInLoveValue(a->getInLoveValue()+1);
|
||||
setInLoveValue(getInLoveValue()+1);
|
||||
loveTime++;
|
||||
if (loveTime % 4 == 0)
|
||||
{
|
||||
level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, 0, 0, 0);
|
||||
}
|
||||
|
||||
if (loveTime == 20 * 3) breedWith(a);
|
||||
}
|
||||
else loveTime = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
loveTime = 0;
|
||||
attackTarget = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Animal::breedWith(shared_ptr<Animal> target)
|
||||
{
|
||||
shared_ptr<AgableMob> offspring = getBreedOffspring(target);
|
||||
|
||||
setInLoveValue(0);
|
||||
loveTime = 0;
|
||||
attackTarget = nullptr;
|
||||
target->attackTarget = nullptr;
|
||||
target->loveTime = 0;
|
||||
target->setInLoveValue(0);
|
||||
|
||||
// 4J - we have offspring of NULL returned when we have hit our limits of spawning any particular type of animal. In these cases try and do everything we can apart from actually
|
||||
// spawning the entity.
|
||||
if (offspring != NULL)
|
||||
{
|
||||
// Only want to set the age to this +ve value if something is actually spawned, as during this period the animal will attempt to follow offspring and ignore players.
|
||||
setAge(5 * 60 * 20);
|
||||
target->setAge(5 * 60 * 20);
|
||||
|
||||
offspring->setAge(-20 * 60 * 20);
|
||||
offspring->moveTo(x, y, z, yRot, xRot);
|
||||
offspring->setDespawnProtected();
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
double xa = random->nextGaussian() * 0.02;
|
||||
double ya = random->nextGaussian() * 0.02;
|
||||
double za = random->nextGaussian() * 0.02;
|
||||
level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za);
|
||||
}
|
||||
level->addEntity(offspring);
|
||||
|
||||
level->addEntity( shared_ptr<ExperienceOrb>( new ExperienceOrb(level, x, y, z, random->nextInt(4) + 1) ) );
|
||||
}
|
||||
|
||||
setDespawnProtected();
|
||||
}
|
||||
|
||||
float Animal::getWalkTargetValue(int x, int y, int z)
|
||||
{
|
||||
if (level->getTile(x, y - 1, z) == Tile::grass_Id) return 10;
|
||||
return level->getBrightness(x, y, z) - 0.5f;
|
||||
}
|
||||
|
||||
bool Animal::hurt(DamageSource *dmgSource, int dmg)
|
||||
{
|
||||
if (dynamic_cast<EntityDamageSource *>(dmgSource) != NULL)
|
||||
{
|
||||
shared_ptr<Entity> source = dmgSource->getDirectEntity();
|
||||
|
||||
if (dynamic_pointer_cast<Player>(source) != NULL && !dynamic_pointer_cast<Player>(source)->isAllowedToAttackAnimals() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (source != NULL && source->GetType() == eTYPE_ARROW)
|
||||
{
|
||||
shared_ptr<Arrow> arrow = dynamic_pointer_cast<Arrow>(source);
|
||||
if (dynamic_pointer_cast<Player>(arrow->owner) != NULL && ! dynamic_pointer_cast<Player>(arrow->owner)->isAllowedToAttackAnimals() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fleeTime = 20 * 3;
|
||||
attackTarget = nullptr;
|
||||
setInLoveValue(0);
|
||||
|
||||
return AgableMob::hurt(dmgSource, dmg);
|
||||
}
|
||||
|
||||
void Animal::addAdditonalSaveData(CompoundTag *tag)
|
||||
{
|
||||
AgableMob::addAdditonalSaveData(tag);
|
||||
tag->putInt(L"InLove", getInLoveValue());
|
||||
}
|
||||
|
||||
void Animal::readAdditionalSaveData(CompoundTag *tag)
|
||||
{
|
||||
AgableMob::readAdditionalSaveData(tag);
|
||||
setInLoveValue(tag->getInt(L"InLove"));
|
||||
setDespawnProtected();
|
||||
}
|
||||
|
||||
shared_ptr<Entity> Animal::findAttackTarget()
|
||||
{
|
||||
if (fleeTime > 0) return nullptr;
|
||||
|
||||
float r = 8;
|
||||
if (getInLoveValue() > 0)
|
||||
{
|
||||
vector<shared_ptr<Entity> > *others = level->getEntitiesOfClass(typeid(*this), bb->grow(r, r, r));
|
||||
//for (int i = 0; i < others->size(); i++)
|
||||
for(AUTO_VAR(it, others->begin()); it != others->end(); ++it)
|
||||
{
|
||||
shared_ptr<Animal> p = dynamic_pointer_cast<Animal>(*it);
|
||||
if (p != shared_from_this() && p->getInLoveValue() > 0)
|
||||
{
|
||||
delete others;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
delete others;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getAge() == 0)
|
||||
{
|
||||
vector<shared_ptr<Entity> > *players = level->getEntitiesOfClass(typeid(Player), bb->grow(r, r, r));
|
||||
//for (int i = 0; i < players.size(); i++)
|
||||
for(AUTO_VAR(it, players->begin()); it != players->end(); ++it)
|
||||
{
|
||||
setDespawnProtected();
|
||||
|
||||
shared_ptr<Player> p = dynamic_pointer_cast<Player>(*it);
|
||||
if (p->getSelectedItem() != NULL && this->isFood(p->getSelectedItem()))
|
||||
{
|
||||
delete players;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
delete players;
|
||||
}
|
||||
else if (getAge() > 0)
|
||||
{
|
||||
vector<shared_ptr<Entity> > *others = level->getEntitiesOfClass(typeid(*this), bb->grow(r, r, r));
|
||||
//for (int i = 0; i < others.size(); i++)
|
||||
for(AUTO_VAR(it, others->begin()); it != others->end(); ++it)
|
||||
{
|
||||
shared_ptr<Animal> p = dynamic_pointer_cast<Animal>(*it);
|
||||
if (p != shared_from_this() && p->getAge() < 0)
|
||||
{
|
||||
delete others;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
delete others;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Animal::canSpawn()
|
||||
{
|
||||
int xt = Mth::floor(x);
|
||||
int yt = Mth::floor(bb->y0);
|
||||
int zt = Mth::floor(z);
|
||||
return level->getTile(xt, yt - 1, zt) == Tile::grass_Id && level->getDaytimeRawBrightness(xt, yt, zt) > 8 && AgableMob::canSpawn();
|
||||
}
|
||||
|
||||
int Animal::getAmbientSoundInterval()
|
||||
{
|
||||
return 20 * 6;
|
||||
}
|
||||
|
||||
bool Animal::removeWhenFarAway()
|
||||
{
|
||||
return !isDespawnProtected(); // 4J changed - was false
|
||||
}
|
||||
|
||||
int Animal::getExperienceReward(shared_ptr<Player> killedBy)
|
||||
{
|
||||
return 1 + level->random->nextInt(3);
|
||||
}
|
||||
|
||||
bool Animal::isFood(shared_ptr<ItemInstance> itemInstance)
|
||||
{
|
||||
return itemInstance->id == Item::wheat_Id;
|
||||
}
|
||||
|
||||
bool Animal::interact(shared_ptr<Player> player)
|
||||
{
|
||||
shared_ptr<ItemInstance> item = player->inventory->getSelected();
|
||||
if (item != NULL && isFood(item) && getAge() == 0)
|
||||
{
|
||||
if (!player->abilities.instabuild)
|
||||
{
|
||||
item->count--;
|
||||
if (item->count <= 0)
|
||||
{
|
||||
player->inventory->setItem(player->inventory->selected, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 4J-PB - If we can't produce another animal through breeding because of the spawn limits, display a message here
|
||||
if(!level->isClientSide)
|
||||
{
|
||||
switch(GetType())
|
||||
{
|
||||
case eTYPE_CHICKEN:
|
||||
if( !level->canCreateMore(eTYPE_CHICKEN, Level::eSpawnType_Breed) )
|
||||
{
|
||||
player->displayClientMessage(IDS_MAX_CHICKENS_BRED );
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case eTYPE_WOLF:
|
||||
if( !level->canCreateMore(eTYPE_WOLF, Level::eSpawnType_Breed) )
|
||||
{
|
||||
player->displayClientMessage(IDS_MAX_WOLVES_BRED );
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case eTYPE_MUSHROOMCOW:
|
||||
if( !level->canCreateMore(eTYPE_MUSHROOMCOW, Level::eSpawnType_Breed) )
|
||||
{
|
||||
player->displayClientMessage(IDS_MAX_MUSHROOMCOWS_BRED );
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if((GetType() & eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) == eTYPE_ANIMALS_SPAWN_LIMIT_CHECK)
|
||||
{
|
||||
if( !level->canCreateMore(GetType(), Level::eSpawnType_Breed) )
|
||||
{
|
||||
player->displayClientMessage(IDS_MAX_PIGS_SHEEP_COWS_CATS_BRED );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if( (GetType() & eTYPE_MONSTER) == eTYPE_MONSTER)
|
||||
{
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
setInLove(player);
|
||||
}
|
||||
|
||||
|
||||
attackTarget = nullptr;
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
double xa = random->nextGaussian() * 0.02;
|
||||
double ya = random->nextGaussian() * 0.02;
|
||||
double za = random->nextGaussian() * 0.02;
|
||||
level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return AgableMob::interact(player);
|
||||
}
|
||||
|
||||
// 4J added
|
||||
int Animal::getInLoveValue()
|
||||
{
|
||||
return entityData->getInteger(DATA_IN_LOVE);
|
||||
}
|
||||
|
||||
void Animal::setInLoveValue(int value)
|
||||
{
|
||||
entityData->set(DATA_IN_LOVE, value);
|
||||
}
|
||||
|
||||
// 4J added
|
||||
void Animal::setInLove(shared_ptr<Player> player)
|
||||
{
|
||||
loveCause = player;
|
||||
setInLoveValue(20*30);
|
||||
}
|
||||
|
||||
shared_ptr<Player> Animal::getLoveCause()
|
||||
{
|
||||
return loveCause.lock();
|
||||
}
|
||||
|
||||
bool Animal::isInLove()
|
||||
{
|
||||
return entityData->getInteger(DATA_IN_LOVE) > 0;
|
||||
}
|
||||
|
||||
void Animal::resetLove() {
|
||||
entityData->set(DATA_IN_LOVE, 0);
|
||||
}
|
||||
|
||||
bool Animal::canMate(shared_ptr<Animal> partner)
|
||||
{
|
||||
if (partner == shared_from_this()) return false;
|
||||
if (typeid(*partner) != typeid(*this)) return false;
|
||||
return isInLove() && partner->isInLove();
|
||||
}
|
||||
|
||||
void Animal::updateDespawnProtectedState()
|
||||
{
|
||||
if( level->isClientSide ) return;
|
||||
|
||||
if( m_isDespawnProtected )
|
||||
{
|
||||
int xt = Mth::floor(x);
|
||||
int zt = Mth::floor(z);
|
||||
|
||||
if ( xt > m_maxWanderX ) m_maxWanderX = xt;
|
||||
if ( xt < m_minWanderX ) m_minWanderX = xt;
|
||||
if ( zt > m_maxWanderZ ) m_maxWanderZ = zt;
|
||||
if ( zt < m_minWanderZ ) m_minWanderZ = zt;
|
||||
|
||||
if( ( ( m_maxWanderX - m_minWanderX ) > MAX_WANDER_DISTANCE ) ||
|
||||
( ( m_maxWanderZ - m_minWanderZ ) > MAX_WANDER_DISTANCE ) )
|
||||
{
|
||||
// printf("Unprotecting : %d to %d, %d to %d\n", m_minWanderX, m_maxWanderX, m_minWanderZ, m_maxWanderZ );
|
||||
m_isDespawnProtected = false;
|
||||
}
|
||||
|
||||
/*
|
||||
if( isExtraWanderingEnabled() )
|
||||
{
|
||||
printf("%d: %d %d, %d\n",entityId,m_maxWanderX - m_minWanderX, m_maxWanderZ - m_minWanderZ, getWanderingQuadrant());
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
bool Animal::isDespawnProtected()
|
||||
{
|
||||
return m_isDespawnProtected;
|
||||
}
|
||||
|
||||
void Animal::setDespawnProtected()
|
||||
{
|
||||
if( level && level->isClientSide ) return;
|
||||
|
||||
int xt = Mth::floor(x);
|
||||
int zt = Mth::floor(z);
|
||||
|
||||
m_minWanderX = xt;
|
||||
m_maxWanderX = xt;
|
||||
m_minWanderZ = zt;
|
||||
m_maxWanderZ = zt;
|
||||
|
||||
m_isDespawnProtected = true;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
#include "AgableMob.h"
|
||||
#include "Creature.h"
|
||||
|
||||
class Level;
|
||||
class CompoundTag;
|
||||
class DamageSource;
|
||||
|
||||
class Animal : public AgableMob, public Creature
|
||||
{
|
||||
private:
|
||||
static const int DATA_IN_LOVE = 13; // 4J added
|
||||
|
||||
// int inLove; // 4J removed - now synched data
|
||||
int loveTime;
|
||||
weak_ptr<Player> loveCause;
|
||||
|
||||
public:
|
||||
Animal(Level *level);
|
||||
|
||||
protected:
|
||||
virtual void defineSynchedData();
|
||||
virtual void serverAiMobStep();
|
||||
|
||||
public:
|
||||
virtual void aiStep();
|
||||
|
||||
protected:
|
||||
virtual void checkHurtTarget(shared_ptr<Entity> target, float d);
|
||||
|
||||
private:
|
||||
virtual void breedWith(shared_ptr<Animal> target);
|
||||
|
||||
public:
|
||||
virtual float getWalkTargetValue(int x, int y, int z);
|
||||
|
||||
public:
|
||||
virtual bool hurt(DamageSource *source, int dmg);
|
||||
virtual void addAdditonalSaveData(CompoundTag *tag);
|
||||
virtual void readAdditionalSaveData(CompoundTag *tag);
|
||||
|
||||
protected:
|
||||
virtual shared_ptr<Entity> findAttackTarget();
|
||||
|
||||
public:
|
||||
virtual bool canSpawn();
|
||||
virtual int getAmbientSoundInterval();
|
||||
|
||||
protected:
|
||||
virtual bool removeWhenFarAway();
|
||||
virtual int getExperienceReward(shared_ptr<Player> killedBy);
|
||||
|
||||
public:
|
||||
virtual bool isFood(shared_ptr<ItemInstance> itemInstance);
|
||||
virtual bool interact(shared_ptr<Player> player);
|
||||
|
||||
protected:
|
||||
int getInLoveValue(); // 4J added
|
||||
|
||||
public:
|
||||
void setInLoveValue(int value); // 4J added
|
||||
void setInLove(shared_ptr<Player> player); // 4J added, then modified to match latest Java for XboxOne achievements
|
||||
shared_ptr<Player> getLoveCause();
|
||||
bool isInLove();
|
||||
void resetLove();
|
||||
virtual bool canMate(shared_ptr<Animal> partner);
|
||||
|
||||
// 4J added for determining whether animals are enclosed or not
|
||||
private:
|
||||
bool m_isDespawnProtected;
|
||||
|
||||
static const int MAX_WANDER_DISTANCE = 20; // Maximum distance that the entity can wander before being considered as not enclosed & therefore not protected (in tiles)
|
||||
short m_minWanderX, m_maxWanderX; // Bounding x values that this has moved since last being set to protected ( in tiles )
|
||||
short m_minWanderZ, m_maxWanderZ; // Bounding z values that this has moved since last being set to protected ( in tiles )
|
||||
void updateDespawnProtectedState();
|
||||
public:
|
||||
virtual bool isDespawnProtected();
|
||||
virtual void setDespawnProtected();
|
||||
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
#include "stdafx.h"
|
||||
#include <iostream>
|
||||
#include "InputOutputStream.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "PacketListener.h"
|
||||
#include "AnimatePacket.h"
|
||||
|
||||
|
||||
|
||||
AnimatePacket::AnimatePacket()
|
||||
{
|
||||
id = -1;
|
||||
action = 0;
|
||||
}
|
||||
|
||||
AnimatePacket::AnimatePacket(shared_ptr<Entity> e, int action)
|
||||
{
|
||||
id = e->entityId;
|
||||
this->action = action;
|
||||
}
|
||||
|
||||
void AnimatePacket::read(DataInputStream *dis) //throws IOException
|
||||
{
|
||||
id = dis->readInt();
|
||||
action = dis->readByte();
|
||||
}
|
||||
|
||||
void AnimatePacket::write(DataOutputStream *dos) //throws IOException
|
||||
{
|
||||
dos->writeInt(id);
|
||||
dos->writeByte(action);
|
||||
}
|
||||
|
||||
void AnimatePacket::handle(PacketListener *listener)
|
||||
{
|
||||
listener->handleAnimate(shared_from_this());
|
||||
}
|
||||
|
||||
int AnimatePacket::getEstimatedSize()
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include "Packet.h"
|
||||
|
||||
class AnimatePacket : public Packet, public enable_shared_from_this<AnimatePacket>
|
||||
{
|
||||
public:
|
||||
static const int SWING = 1;
|
||||
static const int HURT = 2;
|
||||
static const int WAKE_UP = 3;
|
||||
static const int RESPAWN = 4;
|
||||
static const int EAT = 5; // 1.8.2
|
||||
static const int CRITICAL_HIT = 6;
|
||||
static const int MAGIC_CRITICAL_HIT = 7;
|
||||
|
||||
int id;
|
||||
int action;
|
||||
|
||||
AnimatePacket();
|
||||
AnimatePacket(shared_ptr<Entity> e, int action);
|
||||
|
||||
virtual void read(DataInputStream *dis);
|
||||
virtual void write(DataOutputStream *dos);
|
||||
virtual void handle(PacketListener *listener);
|
||||
virtual int getEstimatedSize();
|
||||
|
||||
public:
|
||||
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AnimatePacket()); }
|
||||
virtual int getId() { return 18; }
|
||||
};
|
||||
@@ -0,0 +1,117 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.entity.player.h"
|
||||
#include "net.minecraft.world.entity.item.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "net.minecraft.world.h"
|
||||
#include "net.minecraft.h"
|
||||
#include "AnvilTile.h"
|
||||
|
||||
const unsigned int AnvilTile::ANVIL_NAMES[ANVIL_NAMES_LENGTH] = { IDS_TILE_ANVIL_INTACT,
|
||||
IDS_TILE_ANVIL_SLIGHTLYDAMAGED,
|
||||
IDS_TILE_ANVIL_VERYDAMAGED,
|
||||
};
|
||||
|
||||
|
||||
wstring AnvilTile::TEXTURE_DAMAGE_NAMES[ANVIL_NAMES_LENGTH] = {
|
||||
L"anvil_top", L"anvil_top_damaged_1", L"anvil_top_damaged_2"
|
||||
};
|
||||
|
||||
AnvilTile::AnvilTile(int id) : HeavyTile(id, Material::heavyMetal, isSolidRender() )
|
||||
{
|
||||
part = PART_BASE;
|
||||
setLightBlock(0);
|
||||
icons = NULL;
|
||||
}
|
||||
|
||||
bool AnvilTile::isCubeShaped()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AnvilTile::isSolidRender(bool isServerLevel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Icon *AnvilTile::getTexture(int face, int data)
|
||||
{
|
||||
if (part == PART_TOP && face == Facing::UP)
|
||||
{
|
||||
int damage = (data >> 2) % ANVIL_NAMES_LENGTH;
|
||||
return icons[damage];
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
void AnvilTile::registerIcons(IconRegister *iconRegister)
|
||||
{
|
||||
icon = iconRegister->registerIcon(L"anvil_base");
|
||||
icons = new Icon*[ANVIL_NAMES_LENGTH];
|
||||
|
||||
for (int i = 0; i < ANVIL_NAMES_LENGTH; i++)
|
||||
{
|
||||
icons[i] = iconRegister->registerIcon(TEXTURE_DAMAGE_NAMES[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void AnvilTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr<Mob> by)
|
||||
{
|
||||
int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3;
|
||||
int dmg = level->getData(x, y, z) >> 2;
|
||||
|
||||
dir = ++dir % 4;
|
||||
if (dir == 0) level->setData(x, y, z, Direction::NORTH | (dmg << 2));
|
||||
if (dir == 1) level->setData(x, y, z, Direction::EAST | (dmg << 2));
|
||||
if (dir == 2) level->setData(x, y, z, Direction::SOUTH | (dmg << 2));
|
||||
if (dir == 3) level->setData(x, y, z, Direction::WEST | (dmg << 2));
|
||||
}
|
||||
|
||||
bool AnvilTile::use(Level *level, int x, int y, int z, shared_ptr<Player> player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly)
|
||||
{
|
||||
if (level->isClientSide)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
player->startRepairing(x, y, z);
|
||||
return true;
|
||||
}
|
||||
|
||||
int AnvilTile::getRenderShape()
|
||||
{
|
||||
return SHAPE_ANVIL;
|
||||
}
|
||||
|
||||
int AnvilTile::getSpawnResourcesAuxValue(int data)
|
||||
{
|
||||
return data >> 2;
|
||||
}
|
||||
|
||||
void AnvilTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr<TileEntity> forceEntity)
|
||||
{
|
||||
int dir = level->getData(x, y, z) & 3;
|
||||
|
||||
if (dir == Direction::EAST || dir == Direction::WEST)
|
||||
{
|
||||
setShape(0, 0, 2 / 16.0f, 1, 1, 1 - 2 / 16.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
setShape(2 / 16.0f, 0, 0, 1 - 2 / 16.0f, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void AnvilTile::falling(shared_ptr<FallingTile> entity)
|
||||
{
|
||||
entity->setHurtsEntities(true);
|
||||
}
|
||||
|
||||
void AnvilTile::onLand(Level *level, int xt, int yt, int zt, int data)
|
||||
{
|
||||
level->levelEvent(LevelEvent::SOUND_ANVIL_LAND, xt, yt, zt, 0);
|
||||
}
|
||||
|
||||
bool AnvilTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "HeavyTile.h"
|
||||
|
||||
class FallingTile;
|
||||
|
||||
class AnvilTile : public HeavyTile
|
||||
{
|
||||
friend class ChunkRebuildData;
|
||||
friend class Tile;
|
||||
public:
|
||||
static const int PART_BASE = 0;
|
||||
static const int PART_JOINT = 1;
|
||||
static const int PART_COLUMN = 2;
|
||||
static const int PART_TOP = 3;
|
||||
|
||||
static const int ANVIL_NAMES_LENGTH = 3;
|
||||
|
||||
static const unsigned int ANVIL_NAMES[ANVIL_NAMES_LENGTH];
|
||||
|
||||
private:
|
||||
static wstring TEXTURE_DAMAGE_NAMES[ANVIL_NAMES_LENGTH];
|
||||
|
||||
public:
|
||||
int part;
|
||||
|
||||
private:
|
||||
Icon **icons;
|
||||
|
||||
protected:
|
||||
AnvilTile(int id);
|
||||
|
||||
public:
|
||||
bool isCubeShaped();
|
||||
bool isSolidRender(bool isServerLevel = false);
|
||||
Icon *getTexture(int face, int data);
|
||||
void registerIcons(IconRegister *iconRegister);
|
||||
void setPlacedBy(Level *level, int x, int y, int z, shared_ptr<Mob> by);
|
||||
bool use(Level *level, int x, int y, int z, shared_ptr<Player> player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false);
|
||||
int getRenderShape();
|
||||
int getSpawnResourcesAuxValue(int data);
|
||||
void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr<TileEntity> forceEntity = shared_ptr<TileEntity>());
|
||||
|
||||
protected:
|
||||
void falling(shared_ptr<FallingTile> entity);
|
||||
|
||||
public:
|
||||
void onLand(Level *level, int xt, int yt, int zt, int data);
|
||||
bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "AnvilTileItem.h"
|
||||
|
||||
AnvilTileItem::AnvilTileItem(Tile *tile) : MultiTextureTileItem(tile->id - 256, tile, (int *)AnvilTile::ANVIL_NAMES, 3)
|
||||
{
|
||||
}
|
||||
|
||||
int AnvilTileItem::getLevelDataForAuxValue(int auxValue)
|
||||
{
|
||||
return auxValue << 2;
|
||||
}
|
||||
|
||||
unsigned int AnvilTileItem::getDescriptionId(int iData)
|
||||
{
|
||||
int damage = iData >> 2;
|
||||
return MultiTextureTileItem::getDescriptionId(damage);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "MultiTextureTileItem.h"
|
||||
|
||||
class AnvilTileItem : public MultiTextureTileItem
|
||||
{
|
||||
public:
|
||||
AnvilTileItem(Tile *tile);
|
||||
|
||||
int getLevelDataForAuxValue(int auxValue);
|
||||
virtual unsigned int getDescriptionId(int iData);
|
||||
private:
|
||||
};
|
||||
@@ -0,0 +1,240 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.entity.animal.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "net.minecraft.world.item.crafting.h"
|
||||
#include "ArmorDyeRecipe.h"
|
||||
|
||||
bool ArmorDyeRecipe::matches(shared_ptr<CraftingContainer> craftSlots, Level *level)
|
||||
{
|
||||
shared_ptr<ItemInstance> target = nullptr;
|
||||
vector<shared_ptr<ItemInstance> > dyes;
|
||||
|
||||
for (int slot = 0; slot < craftSlots->getContainerSize(); slot++)
|
||||
{
|
||||
shared_ptr<ItemInstance> item = craftSlots->getItem(slot);
|
||||
if (item == NULL) continue;
|
||||
|
||||
ArmorItem *armor = dynamic_cast<ArmorItem *>(item->getItem());
|
||||
if (armor)
|
||||
{
|
||||
if (armor->getMaterial() == ArmorItem::ArmorMaterial::CLOTH && target == NULL)
|
||||
{
|
||||
target = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (item->id == Item::dye_powder_Id)
|
||||
{
|
||||
dyes.push_back(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return target != NULL && !dyes.empty();
|
||||
}
|
||||
|
||||
shared_ptr<ItemInstance> ArmorDyeRecipe::assembleDyedArmor(shared_ptr<CraftingContainer> craftSlots)
|
||||
{
|
||||
shared_ptr<ItemInstance> target = nullptr;
|
||||
int colorTotals[3];
|
||||
colorTotals[0] = 0;
|
||||
colorTotals[1] = 0;
|
||||
colorTotals[2] = 0;
|
||||
int intensityTotal = 0;
|
||||
int colourCounts = 0;
|
||||
ArmorItem *armor = NULL;
|
||||
|
||||
if(craftSlots != NULL)
|
||||
{
|
||||
for (int slot = 0; slot < craftSlots->getContainerSize(); slot++)
|
||||
{
|
||||
shared_ptr<ItemInstance> item = craftSlots->getItem(slot);
|
||||
if (item == NULL) continue;
|
||||
|
||||
armor = dynamic_cast<ArmorItem *>(item->getItem());
|
||||
if (armor)
|
||||
{
|
||||
if (armor->getMaterial() == ArmorItem::ArmorMaterial::CLOTH && target == NULL)
|
||||
{
|
||||
target = item->copy();
|
||||
|
||||
if (armor->hasCustomColor(item))
|
||||
{
|
||||
int color = armor->getColor(target);
|
||||
float red = (float) ((color >> 16) & 0xFF) / 0xFF;
|
||||
float green = (float) ((color >> 8) & 0xFF) / 0xFF;
|
||||
float blue = (float) (color & 0xFF) / 0xFF;
|
||||
|
||||
intensityTotal += max(red, max(green, blue)) * 0xFF;
|
||||
|
||||
colorTotals[0] += red * 0xFF;
|
||||
colorTotals[1] += green * 0xFF;
|
||||
colorTotals[2] += blue * 0xFF;
|
||||
colourCounts++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else if (item->id == Item::dye_powder_Id)
|
||||
{
|
||||
int tileData = ClothTile::getTileDataForItemAuxValue(item->getAuxValue());
|
||||
int red = (int) (Sheep::COLOR[tileData][0] * 0xFF);
|
||||
int green = (int) (Sheep::COLOR[tileData][1] * 0xFF);
|
||||
int blue = (int) (Sheep::COLOR[tileData][2] * 0xFF);
|
||||
|
||||
intensityTotal += max(red, max(green, blue));
|
||||
|
||||
colorTotals[0] += red;
|
||||
colorTotals[1] += green;
|
||||
colorTotals[2] += blue;
|
||||
colourCounts++;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (armor == NULL) return nullptr;
|
||||
|
||||
int red = (colorTotals[0] / colourCounts);
|
||||
int green = (colorTotals[1] / colourCounts);
|
||||
int blue = (colorTotals[2] / colourCounts);
|
||||
|
||||
float averageIntensity = (float) intensityTotal / colourCounts;
|
||||
float resultIntensity = (float) max(red, max(green, blue));
|
||||
// System.out.println(averageIntensity + ", " + resultIntensity);
|
||||
|
||||
red = (int) ((float) red * averageIntensity / resultIntensity);
|
||||
green = (int) ((float) green * averageIntensity / resultIntensity);
|
||||
blue = (int) ((float) blue * averageIntensity / resultIntensity);
|
||||
|
||||
int rgb = red;
|
||||
rgb = (rgb << 8) + green;
|
||||
rgb = (rgb << 8) + blue;
|
||||
|
||||
armor->setColor(target, rgb);
|
||||
return target;
|
||||
}
|
||||
|
||||
shared_ptr<ItemInstance> ArmorDyeRecipe::assemble(shared_ptr<CraftingContainer> craftSlots)
|
||||
{
|
||||
return ArmorDyeRecipe::assembleDyedArmor(craftSlots);
|
||||
}
|
||||
|
||||
int ArmorDyeRecipe::size()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
const ItemInstance *ArmorDyeRecipe::getResultItem()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const int ArmorDyeRecipe::getGroup()
|
||||
{
|
||||
return ShapedRecipy::eGroupType_Armour;
|
||||
}
|
||||
|
||||
// 4J-PB
|
||||
bool ArmorDyeRecipe::requires(int iRecipe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void ArmorDyeRecipe::requires(INGREDIENTS_REQUIRED *pIngReq)
|
||||
{
|
||||
//int iCount=0;
|
||||
//bool bFound;
|
||||
//int j;
|
||||
INGREDIENTS_REQUIRED TempIngReq;
|
||||
|
||||
// shapeless doesn't have the 3x3 shape, but we'll just use this to store the ingredients anyway
|
||||
TempIngReq.iIngC=0;
|
||||
TempIngReq.iType = RECIPE_TYPE_2x2; // all the dyes can be made in a 2x2
|
||||
TempIngReq.uiGridA = new unsigned int [9];
|
||||
TempIngReq.iIngIDA= new int [3*3];
|
||||
TempIngReq.iIngValA = new int [3*3];
|
||||
TempIngReq.iIngAuxValA = new int [3*3];
|
||||
|
||||
ZeroMemory(TempIngReq.iIngIDA,sizeof(int)*9);
|
||||
ZeroMemory(TempIngReq.iIngValA,sizeof(int)*9);
|
||||
memset(TempIngReq.iIngAuxValA,Recipes::ANY_AUX_VALUE,sizeof(int)*9);
|
||||
ZeroMemory(TempIngReq.uiGridA,sizeof(unsigned int)*9);
|
||||
|
||||
#if 0
|
||||
AUTO_VAR(citEnd, ingredients->end());
|
||||
|
||||
for (vector<ItemInstance *>::const_iterator ingredient = ingredients->begin(); ingredient != citEnd; ingredient++)
|
||||
{
|
||||
ItemInstance *expected = *ingredient;
|
||||
|
||||
if (expected!=NULL)
|
||||
{
|
||||
int iAuxVal = (*ingredient)->getAuxValue();
|
||||
TempIngReq.uiGridA[iCount++]=expected->id | iAuxVal<<24;
|
||||
// 4J-PB - put the ingredients in boxes 1,2,4,5 so we can see them in a 2x2 crafting screen
|
||||
if(iCount==2) iCount=3;
|
||||
bFound=false;
|
||||
for(j=0;j<TempIngReq.iIngC;j++)
|
||||
{
|
||||
if((TempIngReq.iIngIDA[j]==expected->id) && (iAuxVal == Recipes::ANY_AUX_VALUE || TempIngReq.iIngAuxValA[j] == iAuxVal))
|
||||
{
|
||||
bFound= true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(bFound)
|
||||
{
|
||||
TempIngReq.iIngValA[j]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
TempIngReq.iIngIDA[TempIngReq.iIngC]=expected->id;
|
||||
TempIngReq.iIngAuxValA[TempIngReq.iIngC]=iAuxVal;
|
||||
TempIngReq.iIngValA[TempIngReq.iIngC++]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
pIngReq->iIngIDA = new int [TempIngReq.iIngC];
|
||||
pIngReq->iIngValA = new int [TempIngReq.iIngC];
|
||||
pIngReq->iIngAuxValA = new int [TempIngReq.iIngC];
|
||||
pIngReq->uiGridA = new unsigned int [9];
|
||||
|
||||
pIngReq->pRecipy=this;
|
||||
|
||||
for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
|
||||
{
|
||||
pIngReq->bCanMake[i]=false;
|
||||
}
|
||||
|
||||
pIngReq->iIngC=TempIngReq.iIngC;
|
||||
pIngReq->iType=TempIngReq.iType;
|
||||
|
||||
if(pIngReq->iIngC!=0)
|
||||
{
|
||||
memcpy(pIngReq->iIngIDA,TempIngReq.iIngIDA,sizeof(int)*TempIngReq.iIngC);
|
||||
memcpy(pIngReq->iIngValA,TempIngReq.iIngValA,sizeof(int)*TempIngReq.iIngC);
|
||||
memcpy(pIngReq->iIngAuxValA,TempIngReq.iIngAuxValA,sizeof(int)*TempIngReq.iIngC);
|
||||
}
|
||||
memcpy(pIngReq->uiGridA,TempIngReq.uiGridA,sizeof(unsigned int) *9);
|
||||
|
||||
delete [] TempIngReq.iIngIDA;
|
||||
delete [] TempIngReq.iIngValA;
|
||||
delete [] TempIngReq.iIngAuxValA;
|
||||
delete [] TempIngReq.uiGridA;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "Recipy.h"
|
||||
|
||||
class ArmorDyeRecipe : public Recipy
|
||||
{
|
||||
public:
|
||||
bool matches(shared_ptr<CraftingContainer> craftSlots, Level *level);
|
||||
|
||||
// 4J Stu - Made static as we use this in a different way from the Java (but needs to be a different name otherwise Orbis compiler complains
|
||||
static shared_ptr<ItemInstance> assembleDyedArmor(shared_ptr<CraftingContainer> craftSlots);
|
||||
shared_ptr<ItemInstance> assemble(shared_ptr<CraftingContainer> craftSlots);
|
||||
|
||||
int size();
|
||||
const ItemInstance *getResultItem();
|
||||
|
||||
|
||||
virtual const int getGroup();
|
||||
|
||||
// 4J-PB
|
||||
virtual bool requires(int iRecipe);
|
||||
virtual void requires(INGREDIENTS_REQUIRED *pIngReq);
|
||||
};
|
||||
@@ -0,0 +1,229 @@
|
||||
#include "stdafx.h"
|
||||
#include "..\Minecraft.Client\Minecraft.h"
|
||||
#include "net.minecraft.world.h"
|
||||
#include "net.minecraft.world.entity.player.h"
|
||||
#include "com.mojang.nbt.h"
|
||||
#include "ArmorItem.h"
|
||||
|
||||
const int ArmorItem::healthPerSlot[] = {
|
||||
11, 16, 15, 13
|
||||
};
|
||||
|
||||
const wstring ArmorItem::LEATHER_OVERLAYS[] = {
|
||||
L"helmetCloth_overlay", L"chestplateCloth_overlay", L"leggingsCloth_overlay", L"bootsCloth_overlay"
|
||||
};
|
||||
|
||||
const wstring ArmorItem::TEXTURE_EMPTY_SLOTS[] = {
|
||||
L"slot_empty_helmet", L"slot_empty_chestplate", L"slot_empty_leggings", L"slot_empty_boots"
|
||||
};
|
||||
|
||||
typedef ArmorItem::ArmorMaterial _ArmorMaterial;
|
||||
|
||||
const int _ArmorMaterial::clothArray[] = {1,3,2,1};
|
||||
const int _ArmorMaterial::chainArray[] = {2, 5, 4, 1};
|
||||
const int _ArmorMaterial::ironArray[] = {2, 6, 5, 2};
|
||||
const int _ArmorMaterial::goldArray[] = {2, 5, 3, 1};
|
||||
const int _ArmorMaterial::diamondArray[] = {3, 8, 6, 3};
|
||||
const _ArmorMaterial *_ArmorMaterial::CLOTH = new _ArmorMaterial(5, _ArmorMaterial::clothArray, 15);
|
||||
const _ArmorMaterial *_ArmorMaterial::CHAIN = new _ArmorMaterial(15, _ArmorMaterial::chainArray, 12);
|
||||
const _ArmorMaterial *_ArmorMaterial::IRON = new _ArmorMaterial(15, _ArmorMaterial::ironArray, 9);
|
||||
const _ArmorMaterial *_ArmorMaterial::GOLD = new _ArmorMaterial(7, _ArmorMaterial::goldArray, 25);
|
||||
const _ArmorMaterial *_ArmorMaterial::DIAMOND = new _ArmorMaterial(33, _ArmorMaterial::diamondArray, 10);
|
||||
|
||||
_ArmorMaterial::ArmorMaterial(int durabilityMultiplier, const int slotProtections[], int enchantmentValue)
|
||||
{
|
||||
this->durabilityMultiplier = durabilityMultiplier;
|
||||
this->slotProtections = (int *)slotProtections;
|
||||
this->enchantmentValue = enchantmentValue;
|
||||
}
|
||||
|
||||
_ArmorMaterial::~ArmorMaterial()
|
||||
{
|
||||
delete [] slotProtections;
|
||||
}
|
||||
|
||||
int _ArmorMaterial::getHealthForSlot(int slot) const
|
||||
{
|
||||
return healthPerSlot[slot] * durabilityMultiplier;
|
||||
}
|
||||
|
||||
int _ArmorMaterial::getDefenseForSlot(int slot) const
|
||||
{
|
||||
return slotProtections[slot];
|
||||
}
|
||||
|
||||
int _ArmorMaterial::getEnchantmentValue() const
|
||||
{
|
||||
return enchantmentValue;
|
||||
}
|
||||
|
||||
int _ArmorMaterial::getTierItemId() const
|
||||
{
|
||||
if (this == CLOTH)
|
||||
{
|
||||
return Item::leather_Id;
|
||||
}
|
||||
else if (this == CHAIN)
|
||||
{
|
||||
return Item::ironIngot_Id;
|
||||
}
|
||||
else if (this == GOLD)
|
||||
{
|
||||
return Item::goldIngot_Id;
|
||||
}
|
||||
else if (this == IRON)
|
||||
{
|
||||
return Item::ironIngot_Id;
|
||||
}
|
||||
else if (this == DIAMOND)
|
||||
{
|
||||
return Item::diamond_Id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ArmorItem::ArmorItem(int id, const ArmorMaterial *armorType, int icon, int slot) : Item( id ), armorType( armorType ), slot( slot ), modelIndex( icon ), defense( armorType->getDefenseForSlot(slot) )
|
||||
{
|
||||
setMaxDamage(armorType->getHealthForSlot(slot));
|
||||
maxStackSize = 1;
|
||||
}
|
||||
|
||||
int ArmorItem::getColor(shared_ptr<ItemInstance> item, int spriteLayer)
|
||||
{
|
||||
if (spriteLayer > 0)
|
||||
{
|
||||
return 0xFFFFFF;
|
||||
}
|
||||
|
||||
int color = getColor(item);
|
||||
if (color < 0) color = 0xFFFFFF;
|
||||
return color;
|
||||
}
|
||||
|
||||
//@Override
|
||||
bool ArmorItem::hasMultipleSpriteLayers()
|
||||
{
|
||||
return armorType == ArmorMaterial::CLOTH;
|
||||
}
|
||||
|
||||
int ArmorItem::getEnchantmentValue()
|
||||
{
|
||||
return armorType->getEnchantmentValue();
|
||||
}
|
||||
|
||||
const _ArmorMaterial *ArmorItem::getMaterial()
|
||||
{
|
||||
return armorType;
|
||||
}
|
||||
|
||||
bool ArmorItem::hasCustomColor(shared_ptr<ItemInstance> item)
|
||||
{
|
||||
if (armorType != ArmorMaterial::CLOTH) return false;
|
||||
if (!item->hasTag()) return false;
|
||||
if (!item->getTag()->contains(L"display")) return false;
|
||||
if (!item->getTag()->getCompound(L"display")->contains(L"color")) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int ArmorItem::getColor(shared_ptr<ItemInstance> item)
|
||||
{
|
||||
if (armorType != ArmorMaterial::CLOTH) return -1;
|
||||
|
||||
CompoundTag *tag = item->getTag();
|
||||
if (tag == NULL) return Minecraft::GetInstance()->getColourTable()->getColor( DEFAULT_LEATHER_COLOR );
|
||||
CompoundTag *display = tag->getCompound(L"display");
|
||||
if (display == NULL) return Minecraft::GetInstance()->getColourTable()->getColor( DEFAULT_LEATHER_COLOR );
|
||||
|
||||
if (display->contains(L"color"))
|
||||
{
|
||||
return display->getInt(L"color");
|
||||
}
|
||||
else
|
||||
{
|
||||
return Minecraft::GetInstance()->getColourTable()->getColor( DEFAULT_LEATHER_COLOR );
|
||||
}
|
||||
}
|
||||
|
||||
//@Override
|
||||
Icon *ArmorItem::getLayerIcon(int auxValue, int spriteLayer)
|
||||
{
|
||||
if (spriteLayer == 1)
|
||||
{
|
||||
return overlayIcon;
|
||||
}
|
||||
return Item::getLayerIcon(auxValue, spriteLayer);
|
||||
}
|
||||
|
||||
void ArmorItem::clearColor(shared_ptr<ItemInstance> item)
|
||||
{
|
||||
if (armorType != ArmorMaterial::CLOTH) return;
|
||||
CompoundTag *tag = item->getTag();
|
||||
if (tag == NULL) return;
|
||||
CompoundTag *display = tag->getCompound(L"display");
|
||||
if (display->contains(L"color")) display->remove(L"color");
|
||||
}
|
||||
|
||||
void ArmorItem::setColor(shared_ptr<ItemInstance> item, int color)
|
||||
{
|
||||
if (armorType != ArmorMaterial::CLOTH)
|
||||
{
|
||||
#ifndef _CONTENT_PACKAGE
|
||||
printf("Can't dye non-leather!");
|
||||
__debugbreak();
|
||||
#endif
|
||||
//throw new UnsupportedOperationException("Can't dye non-leather!");
|
||||
}
|
||||
|
||||
CompoundTag *tag = item->getTag();
|
||||
|
||||
if (tag == NULL)
|
||||
{
|
||||
tag = new CompoundTag();
|
||||
item->setTag(tag);
|
||||
}
|
||||
|
||||
CompoundTag *display = tag->getCompound(L"display");
|
||||
if (!tag->contains(L"display")) tag->putCompound(L"display", display);
|
||||
|
||||
display->putInt(L"color", color);
|
||||
}
|
||||
|
||||
bool ArmorItem::isValidRepairItem(shared_ptr<ItemInstance> source, shared_ptr<ItemInstance> repairItem)
|
||||
{
|
||||
if (armorType->getTierItemId() == repairItem->id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return Item::isValidRepairItem(source, repairItem);
|
||||
}
|
||||
|
||||
//@Override
|
||||
void ArmorItem::registerIcons(IconRegister *iconRegister)
|
||||
{
|
||||
Item::registerIcons(iconRegister);
|
||||
|
||||
if (armorType == ArmorMaterial::CLOTH)
|
||||
{
|
||||
overlayIcon = iconRegister->registerIcon(LEATHER_OVERLAYS[slot]);
|
||||
}
|
||||
|
||||
iconEmpty = iconRegister->registerIcon(TEXTURE_EMPTY_SLOTS[slot]);
|
||||
}
|
||||
|
||||
Icon *ArmorItem::getEmptyIcon(int slot)
|
||||
{
|
||||
switch (slot)
|
||||
{
|
||||
case 0:
|
||||
return Item::helmet_diamond->iconEmpty;
|
||||
case 1:
|
||||
return Item::chestplate_diamond->iconEmpty;
|
||||
case 2:
|
||||
return Item::leggings_diamond->iconEmpty;
|
||||
case 3:
|
||||
return Item::boots_diamond->iconEmpty;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include "Item.h"
|
||||
|
||||
class ArmorItem : public Item
|
||||
{
|
||||
public:
|
||||
static const int SLOT_HEAD = 0;
|
||||
static const int SLOT_TORSO = 1;
|
||||
static const int SLOT_LEGS = 2;
|
||||
static const int SLOT_FEET = 3;
|
||||
static const eMinecraftColour DEFAULT_LEATHER_COLOR = eMinecraftColour_Armour_Default_Leather_Colour;
|
||||
|
||||
private:
|
||||
static const int healthPerSlot[];
|
||||
static const wstring LEATHER_OVERLAYS[] ;
|
||||
|
||||
public:
|
||||
static const wstring TEXTURE_EMPTY_SLOTS[];
|
||||
|
||||
public:
|
||||
class ArmorMaterial
|
||||
{
|
||||
public:
|
||||
static const int clothArray[];
|
||||
static const int chainArray[];
|
||||
static const int ironArray[];
|
||||
static const int goldArray[];
|
||||
static const int diamondArray[];
|
||||
public:
|
||||
static const ArmorMaterial *CLOTH;
|
||||
static const ArmorMaterial *CHAIN;
|
||||
static const ArmorMaterial *IRON;
|
||||
static const ArmorMaterial *GOLD;
|
||||
static const ArmorMaterial *DIAMOND;
|
||||
|
||||
private:
|
||||
int durabilityMultiplier;
|
||||
int *slotProtections;
|
||||
int enchantmentValue;
|
||||
|
||||
// 4J Stu - Had to make this public but was private
|
||||
// We shouldn't be creating these except the static initialisation
|
||||
public:
|
||||
ArmorMaterial(int durabilityMultiplier, const int slotProtections[], int enchantmentValue);
|
||||
~ArmorMaterial();
|
||||
|
||||
public:
|
||||
int getHealthForSlot(int slot) const;
|
||||
int getDefenseForSlot(int slot) const;
|
||||
int getEnchantmentValue() const;
|
||||
int getTierItemId() const;
|
||||
};
|
||||
|
||||
const int slot;
|
||||
const int defense;
|
||||
const int modelIndex;
|
||||
|
||||
private:
|
||||
const ArmorMaterial *armorType;
|
||||
Icon *overlayIcon;
|
||||
Icon *iconEmpty;
|
||||
|
||||
public:
|
||||
ArmorItem(int id, const ArmorMaterial *armorType, int icon, int slot);
|
||||
|
||||
//@Override
|
||||
int getColor(shared_ptr<ItemInstance> item, int spriteLayer);
|
||||
|
||||
//@Override
|
||||
bool hasMultipleSpriteLayers();
|
||||
|
||||
virtual int getEnchantmentValue();
|
||||
|
||||
const ArmorMaterial *getMaterial();
|
||||
bool hasCustomColor(shared_ptr<ItemInstance> item);
|
||||
int getColor(shared_ptr<ItemInstance> item);
|
||||
|
||||
//@Override
|
||||
Icon *getLayerIcon(int auxValue, int spriteLayer);
|
||||
void clearColor(shared_ptr<ItemInstance> item);
|
||||
void setColor(shared_ptr<ItemInstance> item, int color);
|
||||
|
||||
bool isValidRepairItem(shared_ptr<ItemInstance> source, shared_ptr<ItemInstance> repairItem);
|
||||
|
||||
//@Override
|
||||
void registerIcons(IconRegister *iconRegister);
|
||||
|
||||
static Icon *getEmptyIcon(int slot);
|
||||
};
|
||||
@@ -0,0 +1,158 @@
|
||||
//package net.minecraft.world.item.crafting;
|
||||
|
||||
//import net.minecraft.world.item.*;
|
||||
//import net.minecraft.world.level.tile.Tile;
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "Tile.h"
|
||||
#include "Recipy.h"
|
||||
#include "Recipes.h"
|
||||
#include "ArmorRecipes.h"
|
||||
|
||||
// 4J-PB - adding "" on the end of these so we can detect it
|
||||
wstring ArmorRecipes::shapes[][4] =
|
||||
{
|
||||
{L"XXX", //
|
||||
L"X X",L""},//
|
||||
|
||||
{L"X X", //
|
||||
L"XXX",//
|
||||
L"XXX",L""},//
|
||||
|
||||
{L"XXX", //
|
||||
L"X X",//
|
||||
L"X X",L""},//
|
||||
|
||||
{L"X X",//
|
||||
L"X X",L""},//
|
||||
};
|
||||
|
||||
/*
|
||||
ArmorRecipes::map[5] =
|
||||
{
|
||||
{Item::leather, Tile::fire, Item::ironIngot, Item::diamond, Item::goldIngot},
|
||||
{Item::helmet_cloth, Item::helmet_chain, Item::helmet_iron, Item::helmet_diamond, Item::helmet_gold},
|
||||
{Item::chestplate_cloth, Item::chestplate_chain, Item::chestplate_iron, Item::chestplate_diamond, Item::chestplate_gold},
|
||||
{Item::leggings_cloth, Item::leggings_chain, Item::leggings_iron, Item::leggings_diamond, Item::leggings_gold},
|
||||
{Item::boots_cloth, Item::boots_chain, Item::boots_iron, Item::boots_diamond, Item::boots_gold},
|
||||
};
|
||||
*/
|
||||
|
||||
void ArmorRecipes::_init()
|
||||
{
|
||||
map = new vector <Object *> [MAX_ARMOUR_RECIPES];
|
||||
|
||||
// 4J-PB - removing the chain armour, since we show all possible recipes in the xbox game, and it's not one you can make
|
||||
ADD_OBJECT(map[0],Item::leather);
|
||||
// ADD_OBJECT(map[0],Tile::fire);
|
||||
ADD_OBJECT(map[0],Item::ironIngot);
|
||||
ADD_OBJECT(map[0],Item::diamond);
|
||||
ADD_OBJECT(map[0],Item::goldIngot);
|
||||
|
||||
ADD_OBJECT(map[1],Item::helmet_cloth);
|
||||
// ADD_OBJECT(map[1],Item::helmet_chain);
|
||||
ADD_OBJECT(map[1],Item::helmet_iron);
|
||||
ADD_OBJECT(map[1],Item::helmet_diamond);
|
||||
ADD_OBJECT(map[1],Item::helmet_gold);
|
||||
|
||||
ADD_OBJECT(map[2],Item::chestplate_cloth);
|
||||
// ADD_OBJECT(map[2],Item::chestplate_chain);
|
||||
ADD_OBJECT(map[2],Item::chestplate_iron);
|
||||
ADD_OBJECT(map[2],Item::chestplate_diamond);
|
||||
ADD_OBJECT(map[2],Item::chestplate_gold);
|
||||
|
||||
ADD_OBJECT(map[3],Item::leggings_cloth);
|
||||
// ADD_OBJECT(map[3],Item::leggings_chain);
|
||||
ADD_OBJECT(map[3],Item::leggings_iron);
|
||||
ADD_OBJECT(map[3],Item::leggings_diamond);
|
||||
ADD_OBJECT(map[3],Item::leggings_gold);
|
||||
|
||||
ADD_OBJECT(map[4],Item::boots_cloth);
|
||||
// ADD_OBJECT(map[4],Item::boots_chain);
|
||||
ADD_OBJECT(map[4],Item::boots_iron);
|
||||
ADD_OBJECT(map[4],Item::boots_diamond);
|
||||
ADD_OBJECT(map[4],Item::boots_gold);
|
||||
}
|
||||
|
||||
// 4J-PB added for quick equip in the inventory
|
||||
ArmorRecipes::_eArmorType ArmorRecipes::GetArmorType(int iId)
|
||||
{
|
||||
switch(iId)
|
||||
{
|
||||
case Item::helmet_cloth_Id:
|
||||
case Item::helmet_chain_Id:
|
||||
case Item::helmet_iron_Id:
|
||||
case Item::helmet_diamond_Id:
|
||||
case Item::helmet_gold_Id:
|
||||
return eArmorType_Helmet;
|
||||
break;
|
||||
|
||||
case Item::chestplate_cloth_Id:
|
||||
case Item::chestplate_chain_Id:
|
||||
case Item::chestplate_iron_Id:
|
||||
case Item::chestplate_diamond_Id:
|
||||
case Item::chestplate_gold_Id:
|
||||
return eArmorType_Chestplate;
|
||||
break;
|
||||
|
||||
case Item::leggings_cloth_Id:
|
||||
case Item::leggings_chain_Id:
|
||||
case Item::leggings_iron_Id:
|
||||
case Item::leggings_diamond_Id:
|
||||
case Item::leggings_gold_Id:
|
||||
return eArmorType_Leggings;
|
||||
break;
|
||||
|
||||
case Item::boots_cloth_Id:
|
||||
case Item::boots_chain_Id:
|
||||
case Item::boots_iron_Id:
|
||||
case Item::boots_diamond_Id:
|
||||
case Item::boots_gold_Id:
|
||||
return eArmorType_Boots;
|
||||
break;
|
||||
}
|
||||
|
||||
return eArmorType_None;
|
||||
}
|
||||
|
||||
void ArmorRecipes::addRecipes(Recipes *r)
|
||||
{
|
||||
wchar_t wchTypes[5];
|
||||
wchTypes[4]=0;
|
||||
|
||||
for (unsigned int m = 0; m < map[0].size(); m++)
|
||||
{
|
||||
Object *pObjMaterial = map[0].at(m);
|
||||
|
||||
for (int t=0; t<MAX_ARMOUR_RECIPES-1; t++)
|
||||
{
|
||||
Item *target = map[t+1].at(m)->item;
|
||||
|
||||
wchTypes[0]=L'w';
|
||||
wchTypes[1]=L'c';
|
||||
wchTypes[3]=L'g';
|
||||
if(pObjMaterial->GetType()==eType_TILE)
|
||||
{
|
||||
wchTypes[2]=L't';
|
||||
r->addShapedRecipy(new ItemInstance(target),
|
||||
wchTypes,
|
||||
shapes[t],
|
||||
|
||||
L'X', pObjMaterial->tile,
|
||||
L'A');
|
||||
}
|
||||
else
|
||||
{
|
||||
// must be Item
|
||||
wchTypes[2]=L'i';
|
||||
r->addShapedRecipy(new ItemInstance(target),
|
||||
wchTypes,
|
||||
shapes[t],
|
||||
|
||||
L'X', pObjMaterial->item,
|
||||
L'A');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//package net.minecraft.world.item.crafting;
|
||||
|
||||
//import net.minecraft.world.item.*;
|
||||
//import net.minecraft.world.level.tile.Tile;
|
||||
#pragma once
|
||||
|
||||
#define MAX_ARMOUR_RECIPES 5
|
||||
class ArmorRecipes
|
||||
{
|
||||
public:
|
||||
enum _eArmorType
|
||||
{
|
||||
eArmorType_None=0,
|
||||
eArmorType_Helmet,
|
||||
eArmorType_Chestplate,
|
||||
eArmorType_Leggings,
|
||||
eArmorType_Boots,
|
||||
}
|
||||
eArmorType;
|
||||
|
||||
// 4J - added for common ctor code
|
||||
void _init();
|
||||
ArmorRecipes() {_init();}
|
||||
private:
|
||||
// 4J-PB - this wasn't static in java, so might not be right
|
||||
static wstring shapes[][4];
|
||||
|
||||
private:
|
||||
vector <Object *> *map;
|
||||
|
||||
public:
|
||||
void addRecipes(Recipes *r);
|
||||
static _eArmorType GetArmorType(int iId);
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "net.minecraft.world.inventory.h"
|
||||
#include "net.minecraft.world.item.crafting.h"
|
||||
#include "ArmorSlot.h"
|
||||
|
||||
ArmorSlot::ArmorSlot(int slotNum, shared_ptr<Container> container, int id, int x, int y)
|
||||
: Slot( container, id, x, y ),
|
||||
slotNum( slotNum )
|
||||
{
|
||||
}
|
||||
|
||||
int ArmorSlot::getMaxStackSize()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ArmorSlot::mayPlace(shared_ptr<ItemInstance> item)
|
||||
{
|
||||
if ( dynamic_cast<ArmorItem *>( item->getItem() ) != NULL)
|
||||
{
|
||||
return dynamic_cast<ArmorItem *>( item->getItem() )->slot == slotNum;
|
||||
}
|
||||
if (item->getItem()->id == Tile::pumpkin_Id || item->getItem()->id == Item::skull_Id)
|
||||
{
|
||||
return slotNum == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Icon *ArmorSlot::getNoItemIcon()
|
||||
{
|
||||
return ArmorItem::getEmptyIcon(slotNum);
|
||||
}
|
||||
|
||||
//
|
||||
//bool ArmorSlot::mayCombine(shared_ptr<ItemInstance> item)
|
||||
//{
|
||||
// shared_ptr<ItemInstance> thisItemI = getItem();
|
||||
// if(thisItemI == NULL || item == NULL) return false;
|
||||
//
|
||||
// ArmorItem *thisItem = (ArmorItem *)thisItemI->getItem();
|
||||
// bool thisIsDyableArmor = thisItem->getMaterial() == ArmorItem::ArmorMaterial::CLOTH;
|
||||
// bool itemIsDye = item->id == Item::dye_powder_Id;
|
||||
// return thisIsDyableArmor && itemIsDye;
|
||||
//}
|
||||
//
|
||||
//shared_ptr<ItemInstance> ArmorSlot::combine(shared_ptr<ItemInstance> item)
|
||||
//{
|
||||
// shared_ptr<CraftingContainer> craftSlots = shared_ptr<CraftingContainer>( new CraftingContainer(NULL, 2, 2) );
|
||||
// craftSlots->setItem(0, item);
|
||||
// craftSlots->setItem(1, getItem()); // Armour item needs to go second
|
||||
// shared_ptr<ItemInstance> result = ArmorDyeRecipe::assembleDyedArmor(craftSlots);
|
||||
// craftSlots->setItem(0, nullptr);
|
||||
// craftSlots->setItem(1, nullptr);
|
||||
// return result;
|
||||
//}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
// 4J Stu Added
|
||||
// In InventoryMenu.java they create an anoymous class while creating some slot. I have moved the content
|
||||
// of that anonymous class to here
|
||||
|
||||
#include "Slot.h"
|
||||
|
||||
class Container;
|
||||
|
||||
class ArmorSlot : public Slot
|
||||
{
|
||||
private:
|
||||
const int slotNum;
|
||||
|
||||
public:
|
||||
ArmorSlot(int slotNum, shared_ptr<Container> container, int id, int x, int y);
|
||||
virtual ~ArmorSlot() {}
|
||||
|
||||
virtual int getMaxStackSize();
|
||||
virtual bool mayPlace(shared_ptr<ItemInstance> item);
|
||||
Icon *getNoItemIcon();
|
||||
//virtual bool mayCombine(shared_ptr<ItemInstance> item); // 4J Added
|
||||
//virtual shared_ptr<ItemInstance> combine(shared_ptr<ItemInstance> item); // 4J Added
|
||||
};
|
||||
@@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
//Note - this is meant to be a really simple wrapper round a pointer just to be able to add a length value to arrays.
|
||||
// As such, it shouldn't delete its data in a destructor as shallow copies will be made of this and we don't want to
|
||||
// free the data just because one of those has gone out of scope
|
||||
template <class T> class arrayWithLength
|
||||
{
|
||||
public:
|
||||
T *data;
|
||||
unsigned int length;
|
||||
arrayWithLength() { data = NULL; length = 0; }
|
||||
arrayWithLength(unsigned int elements, bool bClearArray=true) { assert(elements!=0); data = new T[elements]; if(bClearArray){ memset( data,0,sizeof(T)*elements); } this->length = elements; }
|
||||
|
||||
// 4J Stu Added this ctor so I static init arrays in the Item derivation tree
|
||||
arrayWithLength( T data[], unsigned int elements) { this->data = data; this->length = elements; }
|
||||
|
||||
//~arrayWithLength() { delete[] data; }
|
||||
|
||||
void resize( unsigned int elements )
|
||||
{
|
||||
assert( elements > length );
|
||||
T *temp = new T[elements];
|
||||
memset( temp,0,sizeof(T)*elements);
|
||||
|
||||
if( data != NULL )
|
||||
{
|
||||
std::copy( data, data+length, temp );
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
data = temp;
|
||||
length = elements;
|
||||
}
|
||||
|
||||
T& operator[](unsigned int i) { return data[i]; }
|
||||
T operator[](unsigned int i) const { return data[i]; }
|
||||
};
|
||||
|
||||
// TODO 4J Stu - This looks right, but is it?
|
||||
template <class T> class array2DWithLength
|
||||
{
|
||||
typedef arrayWithLength< T >* _parrayWithLength;
|
||||
public:
|
||||
_parrayWithLength *data;
|
||||
unsigned int length;
|
||||
array2DWithLength() { data = NULL; length = 0; }
|
||||
array2DWithLength(unsigned int dimA, unsigned int dimB)
|
||||
{
|
||||
data = new _parrayWithLength[dimA];
|
||||
this->length = dimA;
|
||||
|
||||
for( unsigned int i = 0; i < length; i++ )
|
||||
data[i] = new arrayWithLength<T>(dimB);
|
||||
}
|
||||
|
||||
_parrayWithLength& operator[](unsigned int i) { return data[i]; }
|
||||
_parrayWithLength operator[](unsigned int i) const { return data[i]; }
|
||||
};
|
||||
|
||||
|
||||
class Biome;
|
||||
class LevelChunk;
|
||||
class Node;
|
||||
class Item;
|
||||
class Tile;
|
||||
class Stat;
|
||||
class MobCategory;
|
||||
class File;
|
||||
class Vertex;
|
||||
class _Polygon; // Renaming as have conflict with Windows Polygon fn
|
||||
class ServerLevel;
|
||||
class MultiPlayerLevel;
|
||||
class Level;
|
||||
class LevelRenderer;
|
||||
class WeighedRandomItem;
|
||||
class WeighedTreasure;
|
||||
class Layer;
|
||||
//class Cube;
|
||||
class ModelPart;
|
||||
class Enchantment;
|
||||
class ClipChunk;
|
||||
|
||||
typedef arrayWithLength<double> doubleArray;
|
||||
typedef arrayWithLength<byte> byteArray;
|
||||
typedef arrayWithLength<char> charArray;
|
||||
typedef arrayWithLength<short> shortArray;
|
||||
typedef arrayWithLength<int> intArray;
|
||||
typedef arrayWithLength<float> floatArray;
|
||||
typedef arrayWithLength<Biome *> BiomeArray;
|
||||
typedef arrayWithLength<LevelChunk *> LevelChunkArray;
|
||||
typedef array2DWithLength<LevelChunk *> LevelChunk2DArray;
|
||||
typedef arrayWithLength<Node *> NodeArray;
|
||||
typedef arrayWithLength<Item *> ItemArray;
|
||||
typedef arrayWithLength<Tile *> TileArray;
|
||||
typedef arrayWithLength<Stat *> StatArray;
|
||||
typedef arrayWithLength<MobCategory *> MobCategoryArray;
|
||||
typedef arrayWithLength<File *> FileArray;
|
||||
typedef arrayWithLength<Vertex *> VertexArray;
|
||||
typedef arrayWithLength<_Polygon *> PolygonArray;
|
||||
typedef arrayWithLength<ServerLevel *> ServerLevelArray;
|
||||
typedef arrayWithLength<MultiPlayerLevel *> MultiPlayerLevelArray;
|
||||
typedef arrayWithLength<Level *> LevelArray;
|
||||
typedef arrayWithLength<LevelRenderer *> LevelRendererArray;
|
||||
typedef arrayWithLength<WeighedRandomItem *> WeighedRandomItemArray;
|
||||
typedef arrayWithLength<WeighedTreasure *> WeighedTreasureArray;
|
||||
typedef arrayWithLength< shared_ptr<Layer> > LayerArray;
|
||||
//typedef arrayWithLength<Cube *> CubeArray;
|
||||
typedef arrayWithLength<ModelPart *> ModelPartArray;
|
||||
typedef arrayWithLength<Enchantment *> EnchantmentArray;
|
||||
typedef arrayWithLength<ClipChunk> ClipChunkArray;
|
||||
|
||||
#include "ItemInstance.h"
|
||||
typedef arrayWithLength<shared_ptr<ItemInstance> > ItemInstanceArray;
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include "ArrayWithLength.h"
|
||||
|
||||
class Arrays
|
||||
{
|
||||
public:
|
||||
static void fill(doubleArray arr, unsigned int from, unsigned int to, double value)
|
||||
{ assert(from >=0); assert( from <= to ); assert( to <= arr.length ); std::fill( arr.data+from, arr.data+to, value ); }
|
||||
|
||||
static void fill(floatArray arr, unsigned int from, unsigned int to, float value)
|
||||
{ assert(from >=0); assert( from <= to ); assert( to <= arr.length ); std::fill( arr.data+from, arr.data+to, value ); }
|
||||
|
||||
static void fill(BiomeArray arr, unsigned int from, unsigned int to, Biome *value)
|
||||
{ assert(from >=0); assert( from <= to ); assert( to <= arr.length ); std::fill( arr.data+from, arr.data+to, value ); }
|
||||
|
||||
static void fill(byteArray arr, unsigned int from, unsigned int to, byte value)
|
||||
{ assert(from >=0); assert( from <= to ); assert( to <= arr.length ); std::fill( arr.data+from, arr.data+to, value ); }
|
||||
|
||||
static void fill(byteArray arr, byte value)
|
||||
{ std::fill( arr.data, arr.data+arr.length, value ); }
|
||||
};
|
||||
@@ -0,0 +1,531 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "net.minecraft.world.entity.player.h"
|
||||
#include "net.minecraft.world.phys.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "net.minecraft.world.damagesource.h"
|
||||
#include "net.minecraft.world.item.enchantment.h"
|
||||
#include "com.mojang.nbt.h"
|
||||
#include "Arrow.h"
|
||||
|
||||
// 4J : WESTY : Added for other award, kill creeper with arrow.
|
||||
#include "net.minecraft.world.entity.monster.h"
|
||||
#include "net.minecraft.stats.h"
|
||||
#include "SoundTypes.h"
|
||||
|
||||
|
||||
|
||||
// base damage, multiplied with velocity
|
||||
const double Arrow::ARROW_BASE_DAMAGE = 2.0f;
|
||||
|
||||
// 4J - added common ctor code.
|
||||
void Arrow::_init()
|
||||
{
|
||||
// 4J Stu - This function call had to be moved here from the Entity ctor to ensure that
|
||||
// the derived version of the function is called
|
||||
this->defineSynchedData();
|
||||
|
||||
xTile = -1;
|
||||
yTile = -1;
|
||||
zTile = -1;
|
||||
lastTile = 0;
|
||||
lastData = 0;
|
||||
inGround = false;
|
||||
pickup = PICKUP_DISALLOWED;
|
||||
shakeTime = 0;
|
||||
flightTime = 0;
|
||||
|
||||
owner = nullptr;
|
||||
life = 0;
|
||||
|
||||
baseDamage = ARROW_BASE_DAMAGE;
|
||||
knockback = 0;
|
||||
}
|
||||
|
||||
|
||||
Arrow::Arrow(Level *level) : Entity( level )
|
||||
{
|
||||
_init();
|
||||
|
||||
this->setSize(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
Arrow::Arrow(Level *level, shared_ptr<Mob> mob, shared_ptr<Mob> target, float power, float uncertainty) : Entity( level )
|
||||
{
|
||||
_init();
|
||||
|
||||
this->owner = mob;
|
||||
if ( dynamic_pointer_cast<Player>( mob ) != NULL) pickup = PICKUP_ALLOWED;
|
||||
|
||||
y = mob->y + mob->getHeadHeight() - 0.1f;
|
||||
|
||||
double xd = target->x - mob->x;
|
||||
double yd = (target->y + target->getHeadHeight() - 0.7f) - y;
|
||||
double zd = target->z - mob->z;
|
||||
double sd = sqrt(xd * xd + zd * zd);
|
||||
if (sd < 0.0000001) return;
|
||||
|
||||
float yRot = (float) (atan2(zd, xd) * 180 / PI) - 90;
|
||||
float xRot = (float) -(atan2(yd, sd) * 180 / PI);
|
||||
|
||||
double xdn = xd / sd;
|
||||
double zdn = zd / sd;
|
||||
moveTo(mob->x + xdn, y, mob->z + zdn, yRot, xRot);
|
||||
heightOffset = 0;
|
||||
|
||||
float yo = (float) sd * 0.2f;
|
||||
shoot(xd, yd + yo, zd, power, uncertainty);
|
||||
}
|
||||
|
||||
Arrow::Arrow(Level *level, double x, double y, double z) : Entity( level )
|
||||
{
|
||||
_init();
|
||||
|
||||
this->setSize(0.5f, 0.5f);
|
||||
|
||||
this->setPos(x, y, z);
|
||||
this->heightOffset = 0;
|
||||
}
|
||||
|
||||
Arrow::Arrow(Level *level, shared_ptr<Mob> mob, float power) : Entity( level )
|
||||
{
|
||||
_init();
|
||||
|
||||
this->owner = mob;
|
||||
if ( dynamic_pointer_cast<Player>( mob ) != NULL) pickup = PICKUP_ALLOWED;
|
||||
|
||||
setSize(0.5f, 0.5f);
|
||||
|
||||
this->moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot);
|
||||
|
||||
x -= Mth::cos(yRot / 180 * PI) * 0.16f;
|
||||
y -= 0.1f;
|
||||
z -= Mth::sin(yRot / 180 * PI) * 0.16f;
|
||||
this->setPos(x, y, z);
|
||||
this->heightOffset = 0;
|
||||
|
||||
xd = -Mth::sin(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI);
|
||||
zd = Mth::cos(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI);
|
||||
yd = -Mth::sin(xRot / 180 * PI);
|
||||
|
||||
shoot(xd, yd, zd, power * 1.5f, 1);
|
||||
}
|
||||
|
||||
|
||||
void Arrow::defineSynchedData()
|
||||
{
|
||||
entityData->define(ID_FLAGS, (byte) 0);
|
||||
}
|
||||
|
||||
|
||||
void Arrow::shoot(double xd, double yd, double zd, float pow, float uncertainty)
|
||||
{
|
||||
float dist = (float) sqrt(xd * xd + yd * yd + zd * zd);
|
||||
|
||||
xd /= dist;
|
||||
yd /= dist;
|
||||
zd /= dist;
|
||||
|
||||
xd += (random->nextGaussian()) * 0.0075f * uncertainty;
|
||||
yd += (random->nextGaussian()) * 0.0075f * uncertainty;
|
||||
zd += (random->nextGaussian()) * 0.0075f * uncertainty;
|
||||
|
||||
xd *= pow;
|
||||
yd *= pow;
|
||||
zd *= pow;
|
||||
|
||||
this->xd = xd;
|
||||
this->yd = yd;
|
||||
this->zd = zd;
|
||||
|
||||
double sd = sqrt(xd * xd + zd * zd);
|
||||
|
||||
yRotO = this->yRot = (float) (atan2(xd, zd) * 180 / PI);
|
||||
xRotO = this->xRot = (float) (atan2(yd, sd) * 180 / PI);
|
||||
life = 0;
|
||||
}
|
||||
|
||||
void Arrow::lerpTo(double x, double y, double z, float yRot, float xRot, int steps)
|
||||
{
|
||||
setPos(x, y, z);
|
||||
setRot(yRot, xRot);
|
||||
}
|
||||
|
||||
void Arrow::lerpMotion(double xd, double yd, double zd)
|
||||
{
|
||||
this->xd = xd;
|
||||
this->yd = yd;
|
||||
this->zd = zd;
|
||||
if (xRotO == 0 && yRotO == 0)
|
||||
{
|
||||
double sd = sqrt(xd * xd + zd * zd);
|
||||
yRotO = this->yRot = (float) (atan2( xd, zd) * 180 / PI);
|
||||
xRotO = this->xRot = (float) (atan2( yd, sd) * 180 / PI);
|
||||
xRotO = xRot;
|
||||
yRotO = yRot;
|
||||
app.DebugPrintf("%f %f : 0x%x\n",xRot,yRot,&yRot);
|
||||
moveTo(x, y, z, yRot, xRot);
|
||||
life = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Arrow::tick()
|
||||
{
|
||||
Entity::tick();
|
||||
|
||||
|
||||
if (xRotO == 0 && yRotO == 0)
|
||||
{
|
||||
double sd = sqrt(xd * xd + zd * zd);
|
||||
yRotO = this->yRot = (float) (atan2(xd, zd) * 180 / PI);
|
||||
xRotO = this->xRot = (float) (atan2(yd, sd) * 180 / PI);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
int t = level->getTile(xTile, yTile, zTile);
|
||||
if (t > 0)
|
||||
{
|
||||
Tile::tiles[t]->updateShape(level, xTile, yTile, zTile);
|
||||
AABB *aabb = Tile::tiles[t]->getAABB(level, xTile, yTile, zTile);
|
||||
if (aabb != NULL && aabb->contains(Vec3::newTemp(x, y, z)))
|
||||
{
|
||||
inGround = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (shakeTime > 0) shakeTime--;
|
||||
|
||||
if (inGround)
|
||||
{
|
||||
int tile = level->getTile(xTile, yTile, zTile);
|
||||
int data = level->getData(xTile, yTile, zTile);
|
||||
if (tile != lastTile || data != lastData)
|
||||
{
|
||||
inGround = false;
|
||||
|
||||
xd *= random->nextFloat() * 0.2f;
|
||||
yd *= random->nextFloat() * 0.2f;
|
||||
zd *= random->nextFloat() * 0.2f;
|
||||
life = 0;
|
||||
flightTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
life++;
|
||||
if (life == 20 * 60) remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
flightTime++;
|
||||
}
|
||||
|
||||
Vec3 *from = Vec3::newTemp(x, y, z);
|
||||
Vec3 *to = Vec3::newTemp(x + xd, y + yd, z + zd);
|
||||
HitResult *res = level->clip(from, to, false, true);
|
||||
|
||||
from = Vec3::newTemp(x, y, z);
|
||||
to = Vec3::newTemp(x + xd, y + yd, z + zd);
|
||||
if (res != NULL)
|
||||
{
|
||||
to = Vec3::newTemp(res->pos->x, res->pos->y, res->pos->z);
|
||||
}
|
||||
shared_ptr<Entity> hitEntity = nullptr;
|
||||
vector<shared_ptr<Entity> > *objects = level->getEntities(shared_from_this(), this->bb->expand(xd, yd, zd)->grow(1, 1, 1));
|
||||
double nearest = 0;
|
||||
AUTO_VAR(itEnd, objects->end());
|
||||
for (AUTO_VAR(it, objects->begin()); it != itEnd; it++)
|
||||
{
|
||||
shared_ptr<Entity> e = *it; //objects->at(i);
|
||||
if (!e->isPickable() || (e == owner && flightTime < 5)) continue;
|
||||
|
||||
float rr = 0.3f;
|
||||
AABB *bb = e->bb->grow(rr, rr, rr);
|
||||
HitResult *p = bb->clip(from, to);
|
||||
if (p != NULL)
|
||||
{
|
||||
double dd = from->distanceTo(p->pos);
|
||||
if (dd < nearest || nearest == 0)
|
||||
{
|
||||
hitEntity = e;
|
||||
nearest = dd;
|
||||
}
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
if (hitEntity != NULL)
|
||||
{
|
||||
delete res;
|
||||
res = new HitResult(hitEntity);
|
||||
}
|
||||
|
||||
if (res != NULL)
|
||||
{
|
||||
if (res->entity != NULL)
|
||||
{
|
||||
float pow = Mth::sqrt(xd * xd + yd * yd + zd * zd);
|
||||
int dmg = (int) Mth::ceil((float)(pow * baseDamage));
|
||||
|
||||
if(isCritArrow()) dmg += random->nextInt(dmg / 2 + 2);
|
||||
|
||||
DamageSource *damageSource = NULL;
|
||||
if (owner == NULL)
|
||||
{
|
||||
damageSource = DamageSource::arrow(dynamic_pointer_cast<Arrow>(shared_from_this()), shared_from_this());
|
||||
}
|
||||
else
|
||||
{
|
||||
damageSource = DamageSource::arrow(dynamic_pointer_cast<Arrow>(shared_from_this()), owner);
|
||||
}
|
||||
|
||||
if(res->entity->hurt(damageSource, dmg))
|
||||
{
|
||||
// Firx for #67839 - Customer Encountered: Bows enchanted with "Flame" still set things on fire if pvp/attack animals is turned off
|
||||
// 4J Stu - We should not set the entity on fire unless we can cause some damage (this doesn't necessarily mean that the arrow hit lowered their health)
|
||||
// set targets on fire first because we want cooked
|
||||
// pork/chicken/steak
|
||||
if (this->isOnFire())
|
||||
{
|
||||
res->entity->setOnFire(5);
|
||||
}
|
||||
|
||||
shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(res->entity);
|
||||
if (mob != NULL)
|
||||
{
|
||||
mob->arrowCount++;
|
||||
if (knockback > 0)
|
||||
{
|
||||
float pushLen = sqrt(xd * xd + zd * zd);
|
||||
if (pushLen > 0)
|
||||
{
|
||||
res->entity->push(xd * knockback * .6f / pushLen, 0.1, zd * knockback * .6f / pushLen);
|
||||
}
|
||||
}
|
||||
|
||||
if (owner != NULL)
|
||||
{
|
||||
ThornsEnchantment::doThornsAfterAttack(owner, mob, random);
|
||||
}
|
||||
}
|
||||
|
||||
// 4J : WESTY : For award, need to track if creeper was killed by arrow from the player.
|
||||
if ( (dynamic_pointer_cast<Player>(owner) != NULL ) && // arrow owner is a player
|
||||
( res->entity->isAlive() == false ) && // target is now dead
|
||||
( dynamic_pointer_cast<Creeper>( res->entity ) != NULL ) ) // target is a creeper
|
||||
|
||||
{
|
||||
dynamic_pointer_cast<Player>(owner)->awardStat(
|
||||
GenericStats::arrowKillCreeper(),
|
||||
GenericStats::param_arrowKillCreeper()
|
||||
);
|
||||
}
|
||||
|
||||
// 4J - sound change brought forward from 1.2.3
|
||||
level->playSound(shared_from_this(), eSoundType_RANDOM_BOW_HIT, 1.0f, 1.2f / (random->nextFloat() * 0.2f + 0.9f));
|
||||
remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
xd *= -0.1f;
|
||||
yd *= -0.1f;
|
||||
zd *= -0.1f;
|
||||
yRot += 180;
|
||||
yRotO += 180;
|
||||
flightTime = 0;
|
||||
}
|
||||
|
||||
delete damageSource;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTile = res->x;
|
||||
yTile = res->y;
|
||||
zTile = res->z;
|
||||
lastTile = level->getTile(xTile, yTile, zTile);
|
||||
lastData = level->getData(xTile, yTile, zTile);
|
||||
xd = (float) (res->pos->x - x);
|
||||
yd = (float) (res->pos->y - y);
|
||||
zd = (float) (res->pos->z - z);
|
||||
float dd = (float) sqrt(xd * xd + yd * yd + zd * zd);
|
||||
// 4J added check - zero dd here was creating NaNs
|
||||
if( dd > 0.0001f )
|
||||
{
|
||||
x -= (xd / dd) * 0.05f;
|
||||
y -= (yd / dd) * 0.05f;
|
||||
z -= (zd / dd) * 0.05f;
|
||||
}
|
||||
|
||||
// 4J - sound change brought forward from 1.2.3
|
||||
level->playSound(shared_from_this(), eSoundType_RANDOM_BOW_HIT, 1.0f, 1.2f / (random->nextFloat() * 0.2f + 0.9f));
|
||||
inGround = true;
|
||||
shakeTime = 7;
|
||||
setCritArrow(false);
|
||||
}
|
||||
}
|
||||
delete res;
|
||||
|
||||
if(isCritArrow())
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
level->addParticle(eParticleType_crit, x + xd * i / 4.0f, y + yd * i / 4.0f, z + zd * i / 4.0f, -xd, -yd + 0.2, -zd);
|
||||
}
|
||||
}
|
||||
|
||||
x += xd;
|
||||
y += yd;
|
||||
z += zd;
|
||||
|
||||
double sd = sqrt(xd * xd + zd * zd);
|
||||
yRot = (float) (atan2(xd, zd) * 180 / PI);
|
||||
xRot = (float) (atan2(yd, sd) * 180 / PI);
|
||||
|
||||
while (xRot - xRotO < -180)
|
||||
xRotO -= 360;
|
||||
while (xRot - xRotO >= 180)
|
||||
xRotO += 360;
|
||||
|
||||
while (yRot - yRotO < -180)
|
||||
yRotO -= 360;
|
||||
while (yRot - yRotO >= 180)
|
||||
yRotO += 360;
|
||||
|
||||
xRot = xRotO + (xRot - xRotO) * 0.2f;
|
||||
yRot = yRotO + (yRot - yRotO) * 0.2f;
|
||||
|
||||
|
||||
float inertia = 0.99f;
|
||||
float gravity = 0.05f;
|
||||
|
||||
if (isInWater())
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
float s = 1 / 4.0f;
|
||||
level->addParticle(eParticleType_bubble, x - xd * s, y - yd * s, z - zd * s, xd, yd, zd);
|
||||
}
|
||||
inertia = 0.80f;
|
||||
}
|
||||
|
||||
xd *= inertia;
|
||||
yd *= inertia;
|
||||
zd *= inertia;
|
||||
yd -= gravity;
|
||||
|
||||
setPos(x, y, z);
|
||||
|
||||
checkInsideTiles();
|
||||
}
|
||||
|
||||
void Arrow::addAdditonalSaveData(CompoundTag *tag)
|
||||
{
|
||||
tag->putShort(L"xTile", (short) xTile);
|
||||
tag->putShort(L"yTile", (short) yTile);
|
||||
tag->putShort(L"zTile", (short) zTile);
|
||||
tag->putByte(L"inTile", (byte) lastTile);
|
||||
tag->putByte(L"inData", (byte) lastData);
|
||||
tag->putByte(L"shake", (byte) shakeTime);
|
||||
tag->putByte(L"inGround", (byte) (inGround ? 1 : 0));
|
||||
tag->putByte(L"pickup", (byte) pickup);
|
||||
tag->putDouble(L"damage", baseDamage);
|
||||
}
|
||||
|
||||
void Arrow::readAdditionalSaveData(CompoundTag *tag)
|
||||
{
|
||||
xTile = tag->getShort(L"xTile");
|
||||
yTile = tag->getShort(L"yTile");
|
||||
zTile = tag->getShort(L"zTile");
|
||||
lastTile = tag->getByte(L"inTile") & 0xff;
|
||||
lastData = tag->getByte(L"inData") & 0xff;
|
||||
shakeTime = tag->getByte(L"shake") & 0xff;
|
||||
inGround = tag->getByte(L"inGround") == 1;
|
||||
if (tag->contains(L"damage"))
|
||||
{
|
||||
baseDamage = tag->getDouble(L"damage");
|
||||
}
|
||||
|
||||
if (tag->contains(L"pickup"))
|
||||
{
|
||||
pickup = tag->getByte(L"pickup");
|
||||
}
|
||||
else if (tag->contains(L"player"))
|
||||
{
|
||||
pickup = tag->getBoolean(L"player") ? PICKUP_ALLOWED : PICKUP_DISALLOWED;
|
||||
}
|
||||
}
|
||||
|
||||
void Arrow::playerTouch(shared_ptr<Player> player)
|
||||
{
|
||||
if (level->isClientSide || !inGround || shakeTime > 0) return;
|
||||
|
||||
bool bRemove = pickup == PICKUP_ALLOWED || (pickup == PICKUP_CREATIVE_ONLY && player->abilities.instabuild);
|
||||
|
||||
if (pickup == PICKUP_ALLOWED)
|
||||
{
|
||||
if (!player->inventory->add( shared_ptr<ItemInstance>( new ItemInstance(Item::arrow, 1) ) ))
|
||||
{
|
||||
bRemove = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bRemove)
|
||||
{
|
||||
level->playSound(shared_from_this(), eSoundType_RANDOM_POP, 0.2f, ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f);
|
||||
player->take(shared_from_this(), 1);
|
||||
remove();
|
||||
}
|
||||
}
|
||||
|
||||
float Arrow::getShadowHeightOffs()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Arrow::setBaseDamage(double baseDamage)
|
||||
{
|
||||
this->baseDamage = baseDamage;
|
||||
}
|
||||
|
||||
double Arrow::getBaseDamage()
|
||||
{
|
||||
return baseDamage;
|
||||
}
|
||||
|
||||
void Arrow::setKnockback(int knockback)
|
||||
{
|
||||
this->knockback = knockback;
|
||||
}
|
||||
|
||||
bool Arrow::isAttackable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Arrow::setCritArrow(bool critArrow)
|
||||
{
|
||||
byte flags = entityData->getByte(ID_FLAGS);
|
||||
if (critArrow)
|
||||
{
|
||||
entityData->set(ID_FLAGS, (byte) (flags | FLAG_CRIT));
|
||||
}
|
||||
else
|
||||
{
|
||||
entityData->set(ID_FLAGS, (byte) (flags & ~FLAG_CRIT));
|
||||
}
|
||||
}
|
||||
|
||||
bool Arrow::isCritArrow()
|
||||
{
|
||||
byte flags = entityData->getByte(ID_FLAGS);
|
||||
return (flags & FLAG_CRIT) != 0;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include "Entity.h"
|
||||
|
||||
class Level;
|
||||
class CompoundTag;
|
||||
|
||||
class Arrow : public Entity
|
||||
{
|
||||
public:
|
||||
eINSTANCEOF GetType() { return eTYPE_ARROW; }
|
||||
static Entity *create(Level *level) { return new Arrow(level); }
|
||||
|
||||
private:
|
||||
// base damage, multiplied with velocity
|
||||
static const double ARROW_BASE_DAMAGE;
|
||||
|
||||
public:
|
||||
static const int PICKUP_DISALLOWED = 0;
|
||||
static const int PICKUP_ALLOWED = 1;
|
||||
static const int PICKUP_CREATIVE_ONLY = 2;
|
||||
|
||||
private:
|
||||
static const int ID_FLAGS = 16;
|
||||
static const int FLAG_CRIT = 1;
|
||||
|
||||
private:
|
||||
int xTile;
|
||||
int yTile;
|
||||
int zTile;
|
||||
int lastTile;
|
||||
int lastData;
|
||||
bool inGround;
|
||||
|
||||
public:
|
||||
int pickup;
|
||||
int shakeTime;
|
||||
shared_ptr<Entity> owner;
|
||||
|
||||
private:
|
||||
double baseDamage;
|
||||
|
||||
int knockback;
|
||||
|
||||
private:
|
||||
int life;
|
||||
int flightTime;
|
||||
|
||||
// 4J - added common ctor code.
|
||||
void _init();
|
||||
|
||||
public:
|
||||
Arrow(Level *level);
|
||||
Arrow(Level *level, shared_ptr<Mob> mob, shared_ptr<Mob> target, float power, float uncertainty);
|
||||
Arrow(Level *level, double x, double y, double z);
|
||||
Arrow(Level *level, shared_ptr<Mob> mob, float power);
|
||||
|
||||
protected:
|
||||
virtual void defineSynchedData();
|
||||
|
||||
public:
|
||||
void shoot(double xd, double yd, double zd, float pow, float uncertainty);
|
||||
virtual void lerpTo(double x, double y, double z, float yRot, float xRot, int steps);
|
||||
virtual void lerpMotion(double xd, double yd, double zd);
|
||||
virtual void tick();
|
||||
virtual void addAdditonalSaveData(CompoundTag *tag);
|
||||
virtual void readAdditionalSaveData(CompoundTag *tag);
|
||||
virtual void playerTouch(shared_ptr<Player> player);
|
||||
virtual float getShadowHeightOffs();
|
||||
|
||||
void setBaseDamage(double baseDamage);
|
||||
double getBaseDamage();
|
||||
void setKnockback(int knockback);
|
||||
virtual bool isAttackable();
|
||||
void setCritArrow(bool critArrow);
|
||||
bool isCritArrow();
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.entity.ai.control.h"
|
||||
#include "net.minecraft.world.entity.ai.navigation.h"
|
||||
#include "net.minecraft.world.entity.ai.sensing.h"
|
||||
#include "net.minecraft.world.entity.projectile.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.phys.h"
|
||||
#include "SoundTypes.h"
|
||||
#include "ArrowAttackGoal.h"
|
||||
|
||||
ArrowAttackGoal::ArrowAttackGoal(Mob *mob, float speed, int projectileType, int attackInterval)
|
||||
{
|
||||
// 4J Init
|
||||
target = weak_ptr<Mob>();
|
||||
attackTime = 0;
|
||||
seeTime = 0;
|
||||
|
||||
this->mob = mob;
|
||||
this->level = mob->level;
|
||||
this->speed = speed;
|
||||
this->projectileType = projectileType;
|
||||
this->attackInterval = attackInterval;
|
||||
setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag);
|
||||
}
|
||||
|
||||
bool ArrowAttackGoal::canUse()
|
||||
{
|
||||
shared_ptr<Mob> bestTarget = mob->getTarget();
|
||||
if (bestTarget == NULL) return false;
|
||||
target = weak_ptr<Mob>(bestTarget);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArrowAttackGoal::canContinueToUse()
|
||||
{
|
||||
return target.lock() != NULL && (canUse() || !mob->getNavigation()->isDone());
|
||||
}
|
||||
|
||||
void ArrowAttackGoal::stop()
|
||||
{
|
||||
target = weak_ptr<Mob>();
|
||||
}
|
||||
|
||||
void ArrowAttackGoal::tick()
|
||||
{
|
||||
double attackRadiusSqr = 10 * 10;
|
||||
shared_ptr<Mob> tar = target.lock();
|
||||
double targetDistSqr = mob->distanceToSqr(tar->x, tar->bb->y0, tar->z);
|
||||
bool canSee = mob->getSensing()->canSee(tar);
|
||||
|
||||
if (canSee)
|
||||
{
|
||||
++seeTime;
|
||||
}
|
||||
else seeTime = 0;
|
||||
|
||||
if (targetDistSqr > attackRadiusSqr || seeTime < 20) mob->getNavigation()->moveTo(tar, speed);
|
||||
else mob->getNavigation()->stop();
|
||||
|
||||
mob->getLookControl()->setLookAt(tar, 30, 30);
|
||||
|
||||
attackTime = max(attackTime - 1, 0);
|
||||
if (attackTime > 0) return;
|
||||
if (targetDistSqr > attackRadiusSqr || !canSee) return;
|
||||
fireAtTarget();
|
||||
attackTime = attackInterval;
|
||||
}
|
||||
|
||||
void ArrowAttackGoal::fireAtTarget()
|
||||
{
|
||||
shared_ptr<Mob> tar = target.lock();
|
||||
if (projectileType == ArrowType)
|
||||
{
|
||||
shared_ptr<Arrow> arrow = shared_ptr<Arrow>( new Arrow(level, dynamic_pointer_cast<Mob>(mob->shared_from_this()), tar, 1.60f, 12) );
|
||||
level->playSound(mob->shared_from_this(), eSoundType_RANDOM_BOW, 1.0f, 1 / (mob->getRandom()->nextFloat() * 0.4f + 0.8f));
|
||||
level->addEntity(arrow);
|
||||
}
|
||||
else if (projectileType == SnowballType)
|
||||
{
|
||||
shared_ptr<Snowball> snowball = shared_ptr<Snowball>( new Snowball(level, dynamic_pointer_cast<Mob>(mob->shared_from_this())) );
|
||||
double xd = tar->x - mob->x;
|
||||
double yd = (tar->y + tar->getHeadHeight() - 1.1f) - snowball->y;
|
||||
double zd = tar->z - mob->z;
|
||||
float yo = sqrt(xd * xd + zd * zd) * 0.2f;
|
||||
snowball->shoot(xd, yd + yo, zd, 1.60f, 12);
|
||||
|
||||
level->playSound(mob->shared_from_this(), eSoundType_RANDOM_BOW, 1.0f, 1 / (mob->getRandom()->nextFloat() * 0.4f + 0.8f));
|
||||
level->addEntity(snowball);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "Goal.h"
|
||||
|
||||
class ArrowAttackGoal : public Goal
|
||||
{
|
||||
public:
|
||||
static const int ArrowType = 1;
|
||||
static const int SnowballType = 2;
|
||||
|
||||
Level *level;
|
||||
Mob *mob; // Owner of this goal
|
||||
weak_ptr<Mob> target;
|
||||
int attackTime;
|
||||
float speed;
|
||||
int seeTime;
|
||||
int projectileType;
|
||||
int attackInterval;
|
||||
|
||||
ArrowAttackGoal(Mob *mob, float speed, int projectileType, int attackInterval);
|
||||
|
||||
virtual bool canUse();
|
||||
virtual bool canContinueToUse();
|
||||
virtual void stop();
|
||||
virtual void tick();
|
||||
|
||||
private:
|
||||
void fireAtTarget();
|
||||
|
||||
public:
|
||||
// 4J Added override to update ai elements when loading entity from schematics
|
||||
virtual void setLevel(Level *level) { this->level = level; }
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "stdafx.h"
|
||||
#include "ArrowDamageEnchantment.h"
|
||||
|
||||
ArrowDamageEnchantment::ArrowDamageEnchantment(int id, int frequency) : Enchantment(id, frequency, EnchantmentCategory::bow)
|
||||
{
|
||||
setDescriptionId(IDS_ENCHANTMENT_ARROW_DAMAGE);
|
||||
}
|
||||
|
||||
int ArrowDamageEnchantment::getMinCost(int level)
|
||||
{
|
||||
return 1 + (level - 1) * 10;
|
||||
}
|
||||
|
||||
int ArrowDamageEnchantment::getMaxCost(int level)
|
||||
{
|
||||
return getMinCost(level) + 15;
|
||||
}
|
||||
|
||||
int ArrowDamageEnchantment::getMaxLevel()
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "Enchantment.h"
|
||||
|
||||
class ArrowDamageEnchantment : public Enchantment
|
||||
{
|
||||
public:
|
||||
ArrowDamageEnchantment(int id, int frequency);
|
||||
|
||||
virtual int getMinCost(int level);
|
||||
virtual int getMaxCost(int level);
|
||||
virtual int getMaxLevel();
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "stdafx.h"
|
||||
#include "ArrowFireEnchantment.h"
|
||||
|
||||
ArrowFireEnchantment::ArrowFireEnchantment(int id, int frequency) : Enchantment(id, frequency, EnchantmentCategory::bow)
|
||||
{
|
||||
setDescriptionId(IDS_ENCHANTMENT_ARROW_FIRE);
|
||||
}
|
||||
|
||||
int ArrowFireEnchantment::getMinCost(int level)
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
int ArrowFireEnchantment::getMaxCost(int level)
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
|
||||
int ArrowFireEnchantment::getMaxLevel()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "Enchantment.h"
|
||||
|
||||
class ArrowFireEnchantment : public Enchantment
|
||||
{
|
||||
public:
|
||||
ArrowFireEnchantment(int id, int frequency);
|
||||
|
||||
virtual int getMinCost(int level);
|
||||
virtual int getMaxCost(int level);
|
||||
virtual int getMaxLevel();
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "stdafx.h"
|
||||
#include "ArrowInfiniteEnchantment.h"
|
||||
|
||||
ArrowInfiniteEnchantment::ArrowInfiniteEnchantment(int id, int frequency) : Enchantment(id, frequency, EnchantmentCategory::bow)
|
||||
{
|
||||
setDescriptionId(IDS_ENCHANTMENT_ARROW_INFINITE);
|
||||
}
|
||||
|
||||
int ArrowInfiniteEnchantment::getMinCost(int level)
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
int ArrowInfiniteEnchantment::getMaxCost(int level)
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
|
||||
int ArrowInfiniteEnchantment::getMaxLevel()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "Enchantment.h"
|
||||
|
||||
class ArrowInfiniteEnchantment : public Enchantment
|
||||
{
|
||||
public:
|
||||
ArrowInfiniteEnchantment(int id, int frequency);
|
||||
|
||||
virtual int getMinCost(int level);
|
||||
virtual int getMaxCost(int level);
|
||||
virtual int getMaxLevel();
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "stdafx.h"
|
||||
#include "ArrowKnockbackEnchantment.h"
|
||||
|
||||
ArrowKnockbackEnchantment::ArrowKnockbackEnchantment(int id, int frequency) : Enchantment(id, frequency, EnchantmentCategory::bow)
|
||||
{
|
||||
setDescriptionId(IDS_ENCHANTMENT_ARROW_KNOCKBACK);
|
||||
}
|
||||
|
||||
int ArrowKnockbackEnchantment::getMinCost(int level)
|
||||
{
|
||||
return 12 + (level - 1) * 20;
|
||||
}
|
||||
|
||||
int ArrowKnockbackEnchantment::getMaxCost(int level)
|
||||
{
|
||||
return getMinCost(level) + 25;
|
||||
}
|
||||
|
||||
int ArrowKnockbackEnchantment::getMaxLevel()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "Enchantment.h"
|
||||
|
||||
class ArrowKnockbackEnchantment : public Enchantment
|
||||
{
|
||||
public:
|
||||
ArrowKnockbackEnchantment(int id, int frequency);
|
||||
|
||||
virtual int getMinCost(int level);
|
||||
virtual int getMaxCost(int level);
|
||||
virtual int getMaxLevel();
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "AuxDataTileItem.h"
|
||||
|
||||
AuxDataTileItem::AuxDataTileItem(int id, Tile *parentTile) : TileItem(id)
|
||||
{
|
||||
this->parentTile = parentTile;
|
||||
|
||||
setMaxDamage(0);
|
||||
setStackedByData(true);
|
||||
}
|
||||
|
||||
Icon *AuxDataTileItem::getIcon(int itemAuxValue)
|
||||
{
|
||||
return parentTile->getTexture(2, itemAuxValue);
|
||||
}
|
||||
|
||||
int AuxDataTileItem::getLevelDataForAuxValue(int auxValue)
|
||||
{
|
||||
return auxValue;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "TileItem.h"
|
||||
|
||||
class Tile;
|
||||
|
||||
class AuxDataTileItem : public TileItem
|
||||
{
|
||||
private:
|
||||
Tile *parentTile;
|
||||
|
||||
public:
|
||||
AuxDataTileItem(int id, Tile *parentTile);
|
||||
|
||||
Icon *getIcon(int itemAuxValue);
|
||||
int getLevelDataForAuxValue(int auxValue);
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.entity.ai.control.h"
|
||||
#include "net.minecraft.world.entity.ai.navigation.h"
|
||||
#include "net.minecraft.world.entity.ai.sensing.h"
|
||||
#include "net.minecraft.world.entity.ai.util.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "net.minecraft.world.entity.animal.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.level.pathfinder.h"
|
||||
#include "net.minecraft.world.phys.h"
|
||||
#include "AvoidPlayerGoal.h"
|
||||
|
||||
AvoidPlayerGoal::AvoidPlayerGoal(PathfinderMob *mob, const type_info& avoidType, float maxDist, float walkSpeed, float sprintSpeed) : avoidType(avoidType)
|
||||
{
|
||||
this->mob = mob;
|
||||
//this->avoidType = avoidType;
|
||||
this->maxDist = maxDist;
|
||||
this->walkSpeed = walkSpeed;
|
||||
this->sprintSpeed = sprintSpeed;
|
||||
this->pathNav = mob->getNavigation();
|
||||
setRequiredControlFlags(Control::MoveControlFlag);
|
||||
|
||||
toAvoid = weak_ptr<Entity>();
|
||||
path = NULL;
|
||||
}
|
||||
|
||||
AvoidPlayerGoal::~AvoidPlayerGoal()
|
||||
{
|
||||
if(path != NULL) delete path;
|
||||
}
|
||||
|
||||
bool AvoidPlayerGoal::canUse()
|
||||
{
|
||||
if (avoidType == typeid(Player))
|
||||
{
|
||||
shared_ptr<TamableAnimal> tamableAnimal = dynamic_pointer_cast<TamableAnimal>(mob->shared_from_this());
|
||||
if (tamableAnimal != NULL && tamableAnimal->isTame()) return false;
|
||||
toAvoid = weak_ptr<Entity>(mob->level->getNearestPlayer(mob->shared_from_this(), maxDist));
|
||||
if (toAvoid.lock() == NULL) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
vector<shared_ptr<Entity> > *entities = mob->level->getEntitiesOfClass(avoidType, mob->bb->grow(maxDist, 3, maxDist));
|
||||
if (entities->empty())
|
||||
{
|
||||
delete entities;
|
||||
return false;
|
||||
}
|
||||
toAvoid = weak_ptr<Entity>(entities->at(0));
|
||||
delete entities;
|
||||
}
|
||||
|
||||
if (!mob->getSensing()->canSee(toAvoid.lock())) return false;
|
||||
|
||||
Vec3 *pos = RandomPos::getPosAvoid(dynamic_pointer_cast<PathfinderMob>(mob->shared_from_this()), 16, 7, Vec3::newTemp(toAvoid.lock()->x, toAvoid.lock()->y, toAvoid.lock()->z));
|
||||
if (pos == NULL) return false;
|
||||
if (toAvoid.lock()->distanceToSqr(pos->x, pos->y, pos->z) < toAvoid.lock()->distanceToSqr(mob->shared_from_this())) return false;
|
||||
delete path;
|
||||
path = pathNav->createPath(pos->x, pos->y, pos->z);
|
||||
if (path == NULL) return false;
|
||||
if (!path->endsInXZ(pos)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AvoidPlayerGoal::canContinueToUse()
|
||||
{
|
||||
return toAvoid.lock() != NULL && !pathNav->isDone();
|
||||
}
|
||||
|
||||
void AvoidPlayerGoal::start()
|
||||
{
|
||||
pathNav->moveTo(path, walkSpeed);
|
||||
path = NULL;
|
||||
}
|
||||
|
||||
void AvoidPlayerGoal::stop()
|
||||
{
|
||||
toAvoid = weak_ptr<Entity>();
|
||||
}
|
||||
|
||||
void AvoidPlayerGoal::tick()
|
||||
{
|
||||
if (mob->distanceToSqr(toAvoid.lock()) < 7 * 7) mob->getNavigation()->setSpeed(sprintSpeed);
|
||||
else mob->getNavigation()->setSpeed(walkSpeed);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "Goal.h"
|
||||
|
||||
class PathNavigation;
|
||||
class PathfinderMob;
|
||||
class Path;
|
||||
|
||||
class AvoidPlayerGoal : public Goal
|
||||
{
|
||||
private:
|
||||
PathfinderMob *mob; // Owner of this goal
|
||||
float walkSpeed, sprintSpeed;
|
||||
weak_ptr<Entity> toAvoid;
|
||||
float maxDist;
|
||||
Path *path;
|
||||
PathNavigation *pathNav;
|
||||
const type_info& avoidType;
|
||||
|
||||
public:
|
||||
AvoidPlayerGoal(PathfinderMob *mob, const type_info& avoidType, float maxDist, float walkSpeed, float sprintSpeed);
|
||||
~AvoidPlayerGoal();
|
||||
|
||||
virtual bool canUse();
|
||||
virtual bool canContinueToUse();
|
||||
virtual void start();
|
||||
virtual void stop();
|
||||
virtual void tick();
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
#include "stdafx.h"
|
||||
#include <iostream>
|
||||
#include "InputOutputStream.h"
|
||||
#include "PacketListener.h"
|
||||
#include "AwardStatPacket.h"
|
||||
|
||||
|
||||
|
||||
AwardStatPacket::AwardStatPacket()
|
||||
{
|
||||
this->m_paramData.data = NULL;
|
||||
this->m_paramData.length = 0;
|
||||
}
|
||||
|
||||
AwardStatPacket::AwardStatPacket(int statId, int count)
|
||||
{
|
||||
this->statId = statId;
|
||||
|
||||
this->m_paramData.data = (byte *) new int(count);
|
||||
this->m_paramData.length = sizeof(int);
|
||||
}
|
||||
|
||||
AwardStatPacket::AwardStatPacket(int statId, byteArray paramData)
|
||||
{
|
||||
this->statId = statId;
|
||||
this->m_paramData = paramData;
|
||||
}
|
||||
|
||||
AwardStatPacket::~AwardStatPacket()
|
||||
{
|
||||
if (m_paramData.data != NULL)
|
||||
{
|
||||
delete [] m_paramData.data;
|
||||
m_paramData.data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void AwardStatPacket::handle(PacketListener *listener)
|
||||
{
|
||||
listener->handleAwardStat(shared_from_this());
|
||||
m_paramData.data = NULL;
|
||||
}
|
||||
|
||||
void AwardStatPacket::read(DataInputStream *dis) //throws IOException
|
||||
{
|
||||
statId = dis->readInt();
|
||||
|
||||
// Read parameter blob.
|
||||
int length = dis->readInt();
|
||||
if(length > 0)
|
||||
{
|
||||
m_paramData = byteArray(length);
|
||||
dis->readFully(m_paramData);
|
||||
}
|
||||
}
|
||||
|
||||
void AwardStatPacket::write(DataOutputStream *dos) //throws IOException
|
||||
{
|
||||
dos->writeInt(statId);
|
||||
dos->writeInt(m_paramData.length);
|
||||
if(m_paramData.length > 0) dos->write(m_paramData);
|
||||
}
|
||||
|
||||
int AwardStatPacket::getEstimatedSize()
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
|
||||
bool AwardStatPacket::isAync()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// On most platforms we only store 'count' in an AwardStatPacket.
|
||||
int AwardStatPacket::getCount()
|
||||
{
|
||||
return *((int*)this->m_paramData.data);
|
||||
}
|
||||
|
||||
// On Durango we store 'Event' parameters here in a blob.
|
||||
byteArray AwardStatPacket::getParamData()
|
||||
{
|
||||
return m_paramData;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include "Packet.h"
|
||||
|
||||
class AwardStatPacket : public Packet, public enable_shared_from_this<AwardStatPacket>
|
||||
{
|
||||
public:
|
||||
int statId;
|
||||
|
||||
// 4J-JEV: Changed to allow for Durango events.
|
||||
protected:
|
||||
byteArray m_paramData;
|
||||
|
||||
public:
|
||||
AwardStatPacket();
|
||||
AwardStatPacket(int statId, int count);
|
||||
AwardStatPacket(int statId, byteArray paramData);
|
||||
~AwardStatPacket();
|
||||
|
||||
virtual void handle(PacketListener *listener);
|
||||
virtual void read(DataInputStream *dis);
|
||||
virtual void write(DataOutputStream *dos);
|
||||
virtual int getEstimatedSize();
|
||||
virtual bool isAync();
|
||||
|
||||
static shared_ptr<Packet> create() { return shared_ptr<Packet>(new AwardStatPacket()); }
|
||||
virtual int getId() { return 200; }
|
||||
|
||||
public:
|
||||
// 4J-JEV: New getters to help prevent unsafe access
|
||||
int getCount();
|
||||
byteArray getParamData();
|
||||
};
|
||||
@@ -0,0 +1,565 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "BasicTree.h"
|
||||
|
||||
byte BasicTree::axisConversionArray[] = { 2, 0, 0, 1, 2, 1 };
|
||||
|
||||
BasicTree::~BasicTree()
|
||||
{
|
||||
delete rnd;
|
||||
|
||||
for( int i = 0; i < foliageCoordsLength; i++ )
|
||||
{
|
||||
delete [] foliageCoords[i];
|
||||
}
|
||||
delete [] foliageCoords;
|
||||
}
|
||||
|
||||
BasicTree::BasicTree(bool doUpdate) : Feature(doUpdate)
|
||||
{
|
||||
rnd = new Random();
|
||||
origin[0] = 0;
|
||||
origin[1] = 0;
|
||||
origin[2] = 0;
|
||||
// Field to hold the tree height.
|
||||
height = 0;
|
||||
// Other important tree information.
|
||||
trunkHeight = 0;
|
||||
trunkHeightScale = 0.618;
|
||||
branchDensity = 1.0;
|
||||
branchSlope = 0.381;
|
||||
widthScale = 1.0;
|
||||
foliageDensity = 1.0;
|
||||
trunkWidth = 1;
|
||||
heightVariance = 12;
|
||||
foliageHeight = 4;
|
||||
foliageCoords = NULL;
|
||||
foliageCoordsLength = 0;
|
||||
}
|
||||
|
||||
void BasicTree::prepare()
|
||||
{
|
||||
// Initialize the instance variables.
|
||||
// Populate the list of foliage cluster locations.
|
||||
// Designed to be overridden in child classes to change basic
|
||||
// tree properties (trunk width, branch angle, foliage density, etc..).
|
||||
trunkHeight = (int) (height * trunkHeightScale);
|
||||
if (trunkHeight >= height) trunkHeight = height - 1;
|
||||
int clustersPerY = (int) (1.382 + pow(foliageDensity * height / 13.0, 2));
|
||||
if (clustersPerY < 1) clustersPerY = 1;
|
||||
// The foliage coordinates are a list of [x,y,z,y of branch base] values for each cluster
|
||||
int **tempFoliageCoords = new int *[clustersPerY * height];
|
||||
for( int i = 0; i < clustersPerY * height; i++ )
|
||||
{
|
||||
tempFoliageCoords[i] = new int[4];
|
||||
}
|
||||
int y = origin[1] + height - foliageHeight;
|
||||
int clusterCount = 1;
|
||||
int trunkTop = origin[1] + trunkHeight;
|
||||
int relativeY = y - origin[1];
|
||||
|
||||
tempFoliageCoords[0][0] = origin[0];
|
||||
tempFoliageCoords[0][1] = y;
|
||||
tempFoliageCoords[0][2] = origin[2];
|
||||
tempFoliageCoords[0][3] = trunkTop;
|
||||
y--;
|
||||
|
||||
while (relativeY >= 0)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
float shapefac = treeShape(relativeY);
|
||||
if (shapefac < 0)
|
||||
{
|
||||
y--;
|
||||
relativeY--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The originOffset is to put the value in the middle of the block.
|
||||
double originOffset = 0.5;
|
||||
while (num < clustersPerY)
|
||||
{
|
||||
double radius = widthScale * (shapefac * (rnd->nextFloat() + 0.328));
|
||||
double angle = rnd->nextFloat() * 2.0 * 3.14159;
|
||||
int x = Mth::floor(radius * sin(angle) + origin[0] + originOffset);
|
||||
int z = Mth::floor(radius * cos(angle) + origin[2] + originOffset);
|
||||
int checkStart[] = { x, y, z };
|
||||
int checkEnd[] = { x, y + foliageHeight, z };
|
||||
// check the center column of the cluster for obstructions.
|
||||
if (checkLine(checkStart, checkEnd) == -1) {
|
||||
// If the cluster can be created, check the branch path
|
||||
// for obstructions.
|
||||
int checkBranchBase[] = { origin[0], origin[1], origin[2] };
|
||||
double distance = sqrt(pow(abs(origin[0] - checkStart[0]), 2.0) + pow(abs(origin[2] - checkStart[2]), 2.0));
|
||||
double branchHeight = distance * branchSlope;
|
||||
if ((checkStart[1] - branchHeight) > trunkTop)
|
||||
{
|
||||
checkBranchBase[1] = trunkTop;
|
||||
}
|
||||
else
|
||||
{
|
||||
checkBranchBase[1] = (int) (checkStart[1] - branchHeight);
|
||||
}
|
||||
// Now check the branch path
|
||||
if (checkLine(checkBranchBase, checkStart) == -1)
|
||||
{
|
||||
// If the branch path is clear, add the position to the list
|
||||
// of foliage positions
|
||||
tempFoliageCoords[clusterCount][0] = x;
|
||||
tempFoliageCoords[clusterCount][1] = y;
|
||||
tempFoliageCoords[clusterCount][2] = z;
|
||||
tempFoliageCoords[clusterCount][3] = checkBranchBase[1];
|
||||
clusterCount++;
|
||||
}
|
||||
}
|
||||
num++;
|
||||
}
|
||||
y--;
|
||||
relativeY--;
|
||||
}
|
||||
// 4J Stu - Rather than copying the array, we are storing the number of valid elements in the array
|
||||
foliageCoordsLength = clusterCount;
|
||||
foliageCoords = tempFoliageCoords;
|
||||
// Delete the rest of the array whilst we still know how big it was
|
||||
for( int i = clusterCount; i < clustersPerY * height; i++ )
|
||||
{
|
||||
delete [] tempFoliageCoords[i];
|
||||
tempFoliageCoords[i] = NULL;
|
||||
}
|
||||
// 4J - original code for above is the following, it isn't obvious to me why it is doing a copy of the array, so let's not for now
|
||||
// foliageCoords = new int[clusterCount][4];
|
||||
// System.arraycopy(tempFoliageCoords, 0, foliageCoords, 0, clusterCount);
|
||||
|
||||
}
|
||||
|
||||
void BasicTree::crossection(int x, int y, int z, float radius, byte direction, int material)
|
||||
{
|
||||
PIXBeginNamedEvent(0, "BasicTree crossection");
|
||||
// Create a circular cross section.
|
||||
//
|
||||
// Used to nearly everything in the foliage, branches, and trunk.
|
||||
// This is a good target for performance optimization.
|
||||
|
||||
// Passed values:
|
||||
// x,y,z is the center location of the cross section
|
||||
// radius is the radius of the section from the center
|
||||
// direction is the direction the cross section is pointed, 0 for x, 1 for y, 2 for z
|
||||
// material is the index number for the material to use
|
||||
int rad = (int) (radius + 0.618);
|
||||
byte secidx1 = axisConversionArray[direction];
|
||||
byte secidx2 = axisConversionArray[direction + 3];
|
||||
int center[] = { x, y, z };
|
||||
int position[] = { 0, 0, 0 };
|
||||
int offset1 = -rad;
|
||||
int offset2 = -rad;
|
||||
int thismat;
|
||||
position[direction] = center[direction];
|
||||
while (offset1 <= rad)
|
||||
{
|
||||
position[secidx1] = center[secidx1] + offset1;
|
||||
offset2 = -rad;
|
||||
while (offset2 <= rad)
|
||||
{
|
||||
double thisdistance = pow(abs(offset1) + 0.5, 2) + pow(abs(offset2) + 0.5, 2);
|
||||
if (thisdistance > radius * radius)
|
||||
{
|
||||
offset2++;
|
||||
continue;
|
||||
}
|
||||
position[secidx2] = center[secidx2] + offset2;
|
||||
PIXBeginNamedEvent(0,"BasicTree getting tile");
|
||||
thismat = thisLevel->getTile(position[0], position[1], position[2]);
|
||||
PIXEndNamedEvent();
|
||||
if (!((thismat == 0) || (thismat == Tile::leaves_Id)))
|
||||
{
|
||||
// If the material of the checked block is anything other than
|
||||
// air or foliage, skip this tile.
|
||||
offset2++;
|
||||
continue;
|
||||
}
|
||||
PIXBeginNamedEvent(0,"BasicTree placing block");
|
||||
placeBlock(thisLevel, position[0], position[1], position[2], material, 0);
|
||||
PIXEndNamedEvent();
|
||||
offset2++;
|
||||
}
|
||||
offset1++;
|
||||
}
|
||||
PIXEndNamedEvent();
|
||||
}
|
||||
|
||||
float BasicTree::treeShape(int y)
|
||||
{
|
||||
// Take the y position relative to the base of the tree.
|
||||
// Return the distance the foliage should be from the trunk axis.
|
||||
// Return a negative number if foliage should not be created at this height.
|
||||
// This method is intended for overriding in child classes, allowing
|
||||
// different shaped trees.
|
||||
// This method should return a consistent value for each y (don't randomize).
|
||||
if (y < (((float) height) * 0.3)) return (float) -1.618;
|
||||
float radius = ((float) height) / ((float) 2.0);
|
||||
float adjacent = (((float) height) / ((float) 2.0)) - y;
|
||||
float distance;
|
||||
if (adjacent == 0) distance = radius;
|
||||
else if (abs(adjacent) >= radius) distance = (float) 0.0;
|
||||
else distance = (float) sqrt(pow(abs(radius), 2) - pow(abs(adjacent), 2));
|
||||
// Alter this factor to change the overall width of the tree.
|
||||
distance *= (float) 0.5;
|
||||
return distance;
|
||||
}
|
||||
|
||||
float BasicTree::foliageShape(int y)
|
||||
{
|
||||
// Take the y position relative to the base of the foliage cluster.
|
||||
// Return the radius of the cluster at this y
|
||||
// Return a negative number if no foliage should be created at this level
|
||||
// this method is intended for overriding in child classes, allowing
|
||||
// foliage of different sizes and shapes.
|
||||
if ((y < 0) || (y >= foliageHeight)) return (float) -1;
|
||||
else if ((y == 0) || (y == (foliageHeight - 1))) return (float) 2;
|
||||
else return (float) 3;
|
||||
}
|
||||
|
||||
void BasicTree::foliageCluster(int x, int y, int z)
|
||||
{
|
||||
PIXBeginNamedEvent(0,"BasicTree foliageCluster");
|
||||
// Generate a cluster of foliage, with the base at x, y, z.
|
||||
// The shape of the cluster is derived from foliageShape
|
||||
// crossection is called to make each level.
|
||||
int topy = y + foliageHeight;
|
||||
int cury = topy - 1;
|
||||
float radius;
|
||||
// 4J Stu - Generate foliage from the top down so that we don't keep recalculating heightmaps
|
||||
while (cury >= y)
|
||||
{
|
||||
radius = foliageShape(cury - y);
|
||||
crossection(x, cury, z, radius, (byte) 1, Tile::leaves_Id);
|
||||
cury--;
|
||||
}
|
||||
PIXEndNamedEvent();
|
||||
}
|
||||
|
||||
void BasicTree::limb(int *start, int *end, int material)
|
||||
{
|
||||
// Create a limb from the start position to the end position.
|
||||
// Used for creating the branches and trunk.
|
||||
|
||||
// Populate delta, the difference between start and end for all three axies.
|
||||
// Set primidx to the index with the largest overall distance traveled.
|
||||
int delta[] = { 0, 0, 0 };
|
||||
byte idx = 0;
|
||||
byte primidx = 0;
|
||||
while (idx < 3)
|
||||
{
|
||||
delta[idx] = end[idx] - start[idx];
|
||||
if (abs(delta[idx]) > abs(delta[primidx]))
|
||||
{
|
||||
primidx = idx;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
// If the largest distance is zero, don't bother to do anything else.
|
||||
if (delta[primidx] == 0) return;
|
||||
// set up the other two axis indices.
|
||||
byte secidx1 = axisConversionArray[primidx];
|
||||
byte secidx2 = axisConversionArray[primidx + 3];
|
||||
// primsign is digit 1 or -1 depending on whether the limb is headed
|
||||
// along the positive or negative primidx axis.
|
||||
char primsign;
|
||||
if (delta[primidx] > 0) primsign = 1;
|
||||
else primsign = -1;
|
||||
// Initilize the per-step movement for the non-primary axies.
|
||||
double secfac1 = ((double) delta[secidx1]) / ((double) delta[primidx]);
|
||||
double secfac2 = ((double) delta[secidx2]) / ((double) delta[primidx]);
|
||||
// Initialize the coordinates.
|
||||
int coordinate[] = { 0, 0, 0 };
|
||||
// Loop through each crossection along the primary axis, from start to end
|
||||
int primoffset = 0;
|
||||
int endoffset = delta[primidx] + primsign;
|
||||
while (primoffset != endoffset)
|
||||
{
|
||||
coordinate[primidx] = Mth::floor(start[primidx] + primoffset + 0.5);
|
||||
coordinate[secidx1] = Mth::floor(start[secidx1] + (primoffset * secfac1) + 0.5);
|
||||
coordinate[secidx2] = Mth::floor(start[secidx2] + (primoffset * secfac2) + 0.5);
|
||||
|
||||
int dir = TreeTile::FACING_Y;
|
||||
int xdiff = abs(coordinate[0] - start[0]);
|
||||
int zdiff = abs(coordinate[2] - start[2]);
|
||||
int maxdiff = max(xdiff, zdiff);
|
||||
|
||||
if (maxdiff > 0)
|
||||
{
|
||||
if (xdiff == maxdiff)
|
||||
{
|
||||
dir = TreeTile::FACING_X;
|
||||
}
|
||||
else if (zdiff == maxdiff)
|
||||
{
|
||||
dir = TreeTile::FACING_Z;
|
||||
}
|
||||
}
|
||||
placeBlock(thisLevel, coordinate[0], coordinate[1], coordinate[2], material, dir);
|
||||
primoffset += primsign;
|
||||
}
|
||||
}
|
||||
|
||||
void BasicTree::makeFoliage()
|
||||
{
|
||||
// Create the tree foliage.
|
||||
// Call foliageCluster at the correct locations
|
||||
int idx = 0;
|
||||
int finish = foliageCoordsLength;
|
||||
while (idx < finish)
|
||||
{
|
||||
int x = foliageCoords[idx][0];
|
||||
int y = foliageCoords[idx][1];
|
||||
int z = foliageCoords[idx][2];
|
||||
foliageCluster(x, y, z);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
bool BasicTree::trimBranches(int localY)
|
||||
{
|
||||
// For larger trees, randomly "prune" the branches so there
|
||||
// aren't too many.
|
||||
// Return true if the branch should be created.
|
||||
// This method is intended for overriding in child classes, allowing
|
||||
// decent amounts of branches on very large trees.
|
||||
// Can also be used to disable branches on some tree types, or
|
||||
// make branches more sparse.
|
||||
if (localY < (height * 0.2)) return false;
|
||||
else return true;
|
||||
}
|
||||
|
||||
void BasicTree::makeTrunk()
|
||||
{
|
||||
// Create the trunk of the tree.
|
||||
int x = origin[0];
|
||||
int startY = origin[1];
|
||||
int topY = origin[1] + trunkHeight;
|
||||
int z = origin[2];
|
||||
int startCoord[] = { x, startY, z };
|
||||
int endCoord[] = { x, topY, z };
|
||||
limb(startCoord, endCoord, Tile::treeTrunk_Id);
|
||||
if (trunkWidth == 2)
|
||||
{
|
||||
startCoord[0] += 1;
|
||||
endCoord[0] += 1;
|
||||
limb(startCoord, endCoord, Tile::treeTrunk_Id);
|
||||
startCoord[2] += 1;
|
||||
endCoord[2] += 1;
|
||||
limb(startCoord, endCoord, Tile::treeTrunk_Id);
|
||||
startCoord[0] += -1;
|
||||
endCoord[0] += -1;
|
||||
limb(startCoord, endCoord, Tile::treeTrunk_Id);
|
||||
}
|
||||
}
|
||||
|
||||
void BasicTree::makeBranches()
|
||||
{
|
||||
// Create the tree branches.
|
||||
// Call trimBranches for each branch to see if you should create it.
|
||||
// Call taperedLimb to the correct locations
|
||||
int idx = 0;
|
||||
int finish = foliageCoordsLength;
|
||||
int baseCoord[] = { origin[0], origin[1], origin[2] };
|
||||
while (idx < finish)
|
||||
{
|
||||
int *coordValues = foliageCoords[idx];
|
||||
int endCoord[] = { coordValues[0], coordValues[1], coordValues[2] };
|
||||
baseCoord[1] = coordValues[3];
|
||||
int localY = baseCoord[1] - origin[1];
|
||||
if (trimBranches(localY))
|
||||
{
|
||||
limb(baseCoord, endCoord, Tile::treeTrunk_Id);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
int BasicTree::checkLine(int *start, int *end)
|
||||
{
|
||||
// Check from coordinates start to end (both inclusive) for blocks other than air and foliage
|
||||
// If a block other than air and foliage is found, return the number of steps taken.
|
||||
// If no block other than air and foliage is found, return -1.
|
||||
// Examples:
|
||||
// If the third block searched is stone, return 2
|
||||
// If the first block searched is lava, return 0
|
||||
|
||||
int delta[] = { 0, 0, 0 };
|
||||
byte idx = 0;
|
||||
byte primidx = 0;
|
||||
while (idx < 3)
|
||||
{
|
||||
delta[idx] = end[idx] - start[idx];
|
||||
if (abs(delta[idx]) > abs(delta[primidx]))
|
||||
{
|
||||
primidx = idx;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
// If the largest distance is zero, don't bother to do anything else.
|
||||
if (delta[primidx] == 0) return -1;
|
||||
// set up the other two axis indices.
|
||||
byte secidx1 = axisConversionArray[primidx];
|
||||
byte secidx2 = axisConversionArray[primidx + 3];
|
||||
// primsign is digit 1 or -1 depending on whether the limb is headed
|
||||
// along the positive or negative primidx axis.
|
||||
char primsign; // 4J Stu - Was byte, but we use in a sum below and byte=unsigned char so we were setting endoffset incorrectly
|
||||
if (delta[primidx] > 0) primsign = 1;
|
||||
else primsign = -1;
|
||||
// Initilize the per-step movement for the non-primary axies.
|
||||
double secfac1 = ((double) delta[secidx1]) / ((double) delta[primidx]);
|
||||
double secfac2 = ((double) delta[secidx2]) / ((double) delta[primidx]);
|
||||
// Initialize the coordinates.
|
||||
int coordinate[] = { 0, 0, 0 };
|
||||
// Loop through each crossection along the primary axis, from start to end
|
||||
int primoffset = 0;
|
||||
int endoffset = delta[primidx] + primsign;
|
||||
int thismat;
|
||||
while (primoffset != endoffset)
|
||||
{
|
||||
coordinate[primidx] = start[primidx] + primoffset;
|
||||
coordinate[secidx1] = Mth::floor(start[secidx1] + (primoffset * secfac1));
|
||||
coordinate[secidx2] = Mth::floor(start[secidx2] + (primoffset * secfac2));
|
||||
thismat = thisLevel->getTile(coordinate[0], coordinate[1], coordinate[2]);
|
||||
if (!((thismat == 0) || (thismat == Tile::leaves_Id)))
|
||||
{
|
||||
// If the material of the checked block is anything other than
|
||||
// air or foliage, stop looking.
|
||||
break;
|
||||
}
|
||||
primoffset += primsign;
|
||||
}
|
||||
// If you reached the end without finding anything, return -1.
|
||||
if (primoffset == endoffset)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// Otherwise, return the number of steps you took.
|
||||
else
|
||||
{
|
||||
return abs(primoffset);
|
||||
}
|
||||
}
|
||||
|
||||
bool BasicTree::checkLocation()
|
||||
{
|
||||
// Return true if the tree can be placed here.
|
||||
// Return false if the tree can not be placed here.
|
||||
|
||||
// Examine the square under the trunk. Is it grass or dirt?
|
||||
// If not, return false
|
||||
// Examine center column for how tall the tree can be.
|
||||
// If the checked height is shorter than height, but taller
|
||||
// than 4, set the tree to the maximum height allowed.
|
||||
// If the space is too short, return false.
|
||||
int startPosition[] = { origin[0], origin[1], origin[2] };
|
||||
int endPosition[] = { origin[0], origin[1] + height - 1, origin[2] };
|
||||
|
||||
// 4J Stu Added to stop tree features generating areas previously place by game rule generation
|
||||
if(app.getLevelGenerationOptions() != NULL)
|
||||
{
|
||||
LevelGenerationOptions *levelGenOptions = app.getLevelGenerationOptions();
|
||||
bool intersects = levelGenOptions->checkIntersects(startPosition[0], startPosition[1], startPosition[2], endPosition[0], endPosition[1], endPosition[2]);
|
||||
if(intersects)
|
||||
{
|
||||
//app.DebugPrintf("Skipping reeds feature generation as it overlaps a game rule structure\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the location it is resting on
|
||||
int baseMaterial = thisLevel->getTile(origin[0], origin[1] - 1, origin[2]);
|
||||
if (!((baseMaterial == 2) || (baseMaterial == 3)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int allowedHeight = checkLine(startPosition, endPosition);
|
||||
// If the set height is good, go with that
|
||||
if (allowedHeight == -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// If the space is too short, tell the build to abort
|
||||
else if (allowedHeight < 6)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// If the space is shorter than the set height, but not too short
|
||||
// shorten the height, and tell the build to continue
|
||||
else
|
||||
{
|
||||
height = allowedHeight;
|
||||
//System.out.println("Shortened the tree");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void BasicTree::init(double heightInit, double widthInit, double foliageDensityInit)
|
||||
{
|
||||
// all of the parameters should be from 0.0 to 1.0
|
||||
// heightInit scales the maximum overall height of the tree (still randomizes height within the possible range)
|
||||
// widthInit scales the maximum overall width of the tree (keep this above 0.3 or so)
|
||||
// foliageDensityInit scales how many foliage clusters are created.
|
||||
//
|
||||
// Note, you can call "place" without calling "init".
|
||||
// This is the same as calling init(1.0,1.0,1.0) and then calling place.
|
||||
heightVariance = (int) (heightInit * 12);
|
||||
if (heightInit > 0.5) foliageHeight = 5;
|
||||
widthScale = widthInit;
|
||||
foliageDensity = foliageDensityInit;
|
||||
}
|
||||
|
||||
bool BasicTree::place(Level *level, Random *random, int x, int y, int z)
|
||||
{
|
||||
// Note to Markus.
|
||||
// currently the following fields are set randomly. If you like, make them
|
||||
// parameters passed into "place".
|
||||
//
|
||||
// height: so the map generator can intelligently set the height of the tree,
|
||||
// and make forests with large trees in the middle and smaller ones on the edges.
|
||||
|
||||
// Initialize the instance fields for the level and the seed.
|
||||
thisLevel = level;
|
||||
__int64 seed = random->nextLong();
|
||||
rnd->setSeed(seed);
|
||||
// Initialize the origin of the tree trunk
|
||||
origin[0] = x;
|
||||
origin[1] = y;
|
||||
origin[2] = z;
|
||||
// Sets the height. Take out this line if height is passed as a parameter
|
||||
if (height == 0)
|
||||
{
|
||||
height = 5 + rnd->nextInt(heightVariance);
|
||||
}
|
||||
if (!(checkLocation()))
|
||||
{
|
||||
//System.out.println("Tree location failed");
|
||||
return false;
|
||||
}
|
||||
PIXBeginNamedEvent(0, "Placing BasicTree");
|
||||
//System.out.println("The height is");
|
||||
//System.out.println(height);
|
||||
//System.out.println("Trunk Height check done");
|
||||
PIXBeginNamedEvent(0, "Preparing tree");
|
||||
prepare();
|
||||
PIXEndNamedEvent();
|
||||
//System.out.println("Prepare done");
|
||||
PIXBeginNamedEvent(0, "Making foliage");
|
||||
makeFoliage();
|
||||
PIXEndNamedEvent();
|
||||
//System.out.println("Foliage done");
|
||||
PIXBeginNamedEvent(0, "Making trunk");
|
||||
makeTrunk();
|
||||
PIXEndNamedEvent();
|
||||
//System.out.println("Trunk done");
|
||||
PIXBeginNamedEvent(0, "Making branches");
|
||||
makeBranches();
|
||||
PIXEndNamedEvent();
|
||||
//System.out.println("Branches done");
|
||||
PIXEndNamedEvent();
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
#include "Feature.h"
|
||||
|
||||
class Level;
|
||||
|
||||
class BasicTree : public Feature
|
||||
{
|
||||
private:
|
||||
// The axisConversionArray, when given a primary index, allows easy
|
||||
// access to the indices of the other two axies. Access the data at the
|
||||
// primary index location to get the horizontal secondary axis.
|
||||
// Access the data at the primary location plus three to get the
|
||||
// remaining, tertiary, axis.
|
||||
// All directions are specified by an index, 0, 1, or 2 which
|
||||
// correspond to x, y, and z.
|
||||
// The axisConversionArray is used in several places
|
||||
// notably the crossection and taperedLimb methods.
|
||||
// Example:
|
||||
// If the primary axis is z, then the primary index is 2.
|
||||
// The secondary index is axisConversionArray[2] which is 0,
|
||||
// the index for the x axis.
|
||||
// The remaining axis is axisConversionArray[2 + 3] which is 1,
|
||||
// the index for the y axis.
|
||||
// Using this method, the secondary axis will always be horizontal (x or z),
|
||||
// and the tertiary always vertical (y), if possible.
|
||||
static byte axisConversionArray[];
|
||||
|
||||
// Set up the pseudorandom number generator
|
||||
Random *rnd;
|
||||
|
||||
// Make fields to hold the level data and the random seed
|
||||
Level *thisLevel;
|
||||
|
||||
// Field to hold the tree origin, x y and z.
|
||||
int origin[3];
|
||||
// Field to hold the tree height.
|
||||
int height;
|
||||
// Other important tree information.
|
||||
int trunkHeight;
|
||||
double trunkHeightScale;
|
||||
double branchDensity;
|
||||
double branchSlope;
|
||||
double widthScale;
|
||||
double foliageDensity;
|
||||
int trunkWidth;
|
||||
int heightVariance;
|
||||
int foliageHeight;
|
||||
// The foliage coordinates are a list of [x,y,z,y of branch base] values for each cluster
|
||||
int **foliageCoords;
|
||||
int foliageCoordsLength;
|
||||
void prepare();
|
||||
void crossection(int x, int y, int z, float radius, byte direction, int material);
|
||||
float treeShape(int y);
|
||||
float foliageShape(int y);
|
||||
void foliageCluster(int x, int y, int z);
|
||||
void limb(int *start, int *end, int material);
|
||||
void makeFoliage();
|
||||
bool trimBranches(int localY);
|
||||
void makeTrunk();
|
||||
void makeBranches();
|
||||
int checkLine(int *start, int *end);
|
||||
bool checkLocation();
|
||||
|
||||
public:
|
||||
BasicTree(bool doUpdate);
|
||||
virtual ~BasicTree();
|
||||
|
||||
virtual void init(double heightInit, double widthInit, double foliageDensityInit);
|
||||
virtual bool place(Level *level, Random *random, int x, int y, int z);
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "stdafx.h"
|
||||
#include "BasicTypeContainers.h"
|
||||
#include <limits>
|
||||
|
||||
|
||||
/* 4J Jev TODO,
|
||||
this is different to Float::MAX_VALUE, javas floats
|
||||
seem to actually allow values of infinity which c++ does not.
|
||||
*/
|
||||
//A constant holding the positive infinity of type float. It is equal to the value returned by Float.intBitsToFloat(0x7f800000).
|
||||
const float Float::POSITIVE_INFINITY = 0x7f800000;
|
||||
|
||||
const float Float::MAX_VALUE = FLT_MAX;
|
||||
|
||||
const double Double::MAX_VALUE = DBL_MAX;
|
||||
|
||||
int Integer::parseInt(wstring &str, int radix /* = 10*/)
|
||||
{
|
||||
return wcstol( str.c_str(), NULL, radix );
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
class Byte
|
||||
{
|
||||
public:
|
||||
static const char MAX_VALUE = CHAR_MAX;
|
||||
static const char MIN_VALUE = CHAR_MIN;
|
||||
};
|
||||
|
||||
class Short
|
||||
{
|
||||
public:
|
||||
static const short MAX_VALUE = SHRT_MAX;
|
||||
static const short MIN_VALUE = SHRT_MIN;
|
||||
};
|
||||
|
||||
class Integer
|
||||
{
|
||||
public:
|
||||
static const int MAX_VALUE = INT_MAX;
|
||||
static int parseInt(wstring &str, int radix = 10);
|
||||
};
|
||||
|
||||
class Float
|
||||
{
|
||||
public:
|
||||
static const float MAX_VALUE;
|
||||
static int floatToIntBits( float value )
|
||||
{
|
||||
return *(int *)&value;
|
||||
}
|
||||
static int floatToRawIntBits( float value )
|
||||
{
|
||||
return *(int *)&value;
|
||||
}
|
||||
|
||||
static float intBitsToFloat( int bits )
|
||||
{
|
||||
return *(float *)&bits;
|
||||
}
|
||||
|
||||
static const float POSITIVE_INFINITY;
|
||||
};
|
||||
|
||||
class Double
|
||||
{
|
||||
public:
|
||||
static const double MAX_VALUE;
|
||||
|
||||
static bool isNaN( double a ) {
|
||||
#ifdef __PS3__
|
||||
return isnan(a);
|
||||
#else
|
||||
return ( a != a );
|
||||
#endif
|
||||
}
|
||||
static bool isInfinite( double a ) { return false; /*4J TODO*/ }
|
||||
|
||||
static double longBitsToDouble( __int64 bits )
|
||||
{
|
||||
return *(double *)&bits;
|
||||
}
|
||||
|
||||
static __int64 doubleToLongBits( double d )
|
||||
{
|
||||
return *(__int64 *)&d;
|
||||
}
|
||||
};
|
||||
|
||||
// 4J Stu - The String class should only be used if we need to use the BaseClass::class type
|
||||
// As such I have renamed it so that we don't confuse it with places where we should use std::string
|
||||
class _String
|
||||
{
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "BiomeDecorator.h"
|
||||
#include "BeachBiome.h"
|
||||
|
||||
BeachBiome::BeachBiome(int id) : Biome(id)
|
||||
{
|
||||
// remove default mob spawn settings
|
||||
friendlies.clear();
|
||||
friendlies_chicken.clear(); // 4J added
|
||||
this->topMaterial = (byte) Tile::sand_Id;
|
||||
this->material = (byte) Tile::sand_Id;
|
||||
|
||||
decorator->treeCount = -999;
|
||||
decorator->deadBushCount = 0;
|
||||
decorator->reedsCount = 0;
|
||||
decorator->cactusCount = 0;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Biome.h"
|
||||
|
||||
class BeachBiome : public Biome
|
||||
{
|
||||
public:
|
||||
BeachBiome(int id);
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.h"
|
||||
#include "net.minecraft.world.entity.player.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "Facing.h"
|
||||
#include "GenericStats.h"
|
||||
#include "BedItem.h"
|
||||
|
||||
BedItem::BedItem(int id) : Item( id )
|
||||
{
|
||||
}
|
||||
|
||||
bool BedItem::useOn(shared_ptr<ItemInstance> itemInstance, shared_ptr<Player> player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly)
|
||||
{
|
||||
if (face != Facing::UP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// place on top of tile
|
||||
y = y + 1;
|
||||
|
||||
BedTile *tile = (BedTile *) Tile::bed;
|
||||
|
||||
int dir = ( Mth::floor(player->yRot * 4 / (360) + 0.5f) ) & 3;
|
||||
int xra = 0;
|
||||
int zra = 0;
|
||||
|
||||
if (dir == Direction::SOUTH) zra = 1;
|
||||
if (dir == Direction::WEST) xra = -1;
|
||||
if (dir == Direction::NORTH) zra = -1;
|
||||
if (dir == Direction::EAST) xra = 1;
|
||||
|
||||
if (!player->mayBuild(x, y, z) || !player->mayBuild(x + xra, y, z + zra)) return false;
|
||||
|
||||
if (level->isEmptyTile(x, y, z) && level->isEmptyTile(x + xra, y, z + zra) && level->isTopSolidBlocking(x, y - 1, z) && level->isTopSolidBlocking(x + xra, y - 1, z + zra))
|
||||
{
|
||||
// 4J-PB - Adding a test only version to allow tooltips to be displayed
|
||||
if(!bTestUseOnOnly)
|
||||
{
|
||||
level->setTileAndData(x, y, z, tile->id, dir);
|
||||
// double-check that the bed was successfully placed
|
||||
if (level->getTile(x, y, z) == tile->id)
|
||||
{
|
||||
// 4J-JEV: Hook for durango 'BlockPlaced' event.
|
||||
player->awardStat(GenericStats::blocksPlaced(tile->id), GenericStats::param_blocksPlaced(tile->id,itemInstance->getAuxValue(),1));
|
||||
|
||||
level->setTileAndData(x + xra, y, z + zra, tile->id, dir + BedTile::HEAD_PIECE_DATA);
|
||||
}
|
||||
|
||||
itemInstance->count--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Item.h"
|
||||
|
||||
class Player;
|
||||
class Level;
|
||||
|
||||
class BedItem : public Item
|
||||
{
|
||||
|
||||
public:
|
||||
BedItem(int id);
|
||||
|
||||
virtual bool useOn(shared_ptr<ItemInstance> itemInstance, shared_ptr<Player> player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false);
|
||||
};
|
||||
@@ -0,0 +1,332 @@
|
||||
#include "stdafx.h"
|
||||
#include "Dimension.h"
|
||||
#include "net.minecraft.h"
|
||||
#include "net.minecraft.world.entity.player.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.h"
|
||||
#include "BedTile.h"
|
||||
|
||||
int BedTile::HEAD_DIRECTION_OFFSETS[4][2] =
|
||||
{
|
||||
{ 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 }
|
||||
};
|
||||
|
||||
BedTile::BedTile(int id) : DirectionalTile(id, Material::cloth, isSolidRender())
|
||||
{
|
||||
setShape();
|
||||
|
||||
iconEnd = NULL;
|
||||
iconSide = NULL;
|
||||
iconTop = NULL;
|
||||
}
|
||||
|
||||
// 4J Added override
|
||||
void BedTile::updateDefaultShape()
|
||||
{
|
||||
setShape();
|
||||
}
|
||||
|
||||
// 4J-PB - Adding a TestUse for tooltip display
|
||||
bool BedTile::TestUse(Level *level, int x, int y, int z, shared_ptr<Player> player)
|
||||
{
|
||||
//if (level->isClientSide) return true;
|
||||
|
||||
int data = level->getData(x, y, z);
|
||||
|
||||
if (!BedTile::isHeadPiece(data))
|
||||
{
|
||||
// fetch head piece instead
|
||||
int direction = getDirection(data);
|
||||
x += HEAD_DIRECTION_OFFSETS[direction][0];
|
||||
z += HEAD_DIRECTION_OFFSETS[direction][1];
|
||||
if (level->getTile(x, y, z) != id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
data = level->getData(x, y, z);
|
||||
}
|
||||
|
||||
if (!level->dimension->mayRespawn())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (BedTile::isOccupied(data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Player::BedSleepingResult result = player->startSleepInBed(x, y, z, true); // true to just test the start sleep
|
||||
if (result == Player::OK)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BedTile::use(Level *level, int x, int y, int z, shared_ptr<Player> player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly/*=false*/) // 4J added soundOnly param
|
||||
{
|
||||
if( soundOnly) return false;
|
||||
if (level->isClientSide) return true;
|
||||
|
||||
int data = level->getData(x, y, z);
|
||||
|
||||
if (!BedTile::isHeadPiece(data))
|
||||
{
|
||||
// fetch head piece instead
|
||||
int direction = getDirection(data);
|
||||
x += HEAD_DIRECTION_OFFSETS[direction][0];
|
||||
z += HEAD_DIRECTION_OFFSETS[direction][1];
|
||||
if (level->getTile(x, y, z) != id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
data = level->getData(x, y, z);
|
||||
}
|
||||
|
||||
if (!level->dimension->mayRespawn())
|
||||
{
|
||||
double xc = x + 0.5;
|
||||
double yc = y + 0.5;
|
||||
double zc = z + 0.5;
|
||||
level->setTile(x, y, z, 0);
|
||||
int direction = getDirection(data);
|
||||
x += HEAD_DIRECTION_OFFSETS[direction][0];
|
||||
z += HEAD_DIRECTION_OFFSETS[direction][1];
|
||||
if (level->getTile(x, y, z) == id) {
|
||||
level->setTile(x, y, z, 0);
|
||||
xc = (xc + x + 0.5) / 2;
|
||||
yc = (yc + y + 0.5) / 2;
|
||||
zc = (zc + z + 0.5) / 2;
|
||||
}
|
||||
level->explode(nullptr, x + 0.5f, y + 0.5f, z + 0.5f, 5, true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (BedTile::isOccupied(data))
|
||||
{
|
||||
shared_ptr<Player> sleepingPlayer = nullptr;
|
||||
AUTO_VAR(itEnd, level->players.end());
|
||||
for (AUTO_VAR(it, level->players.begin()); it != itEnd; it++ )
|
||||
{
|
||||
shared_ptr<Player> p = *it;
|
||||
if (p->isSleeping())
|
||||
{
|
||||
Pos pos = p->bedPosition;
|
||||
if (pos.x == x && pos.y == y && pos.z == z)
|
||||
{
|
||||
sleepingPlayer = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sleepingPlayer == NULL)
|
||||
{
|
||||
BedTile::setOccupied(level, x, y, z, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->displayClientMessage(IDS_TILE_BED_OCCUPIED );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Player::BedSleepingResult result = player->startSleepInBed(x, y, z);
|
||||
if (result == Player::OK)
|
||||
{
|
||||
BedTile::setOccupied(level, x, y, z, true);
|
||||
// 4J-PB added
|
||||
// are there multiple players in the same world as us?
|
||||
if(level->AllPlayersAreSleeping()==false)
|
||||
{
|
||||
player->displayClientMessage(IDS_TILE_BED_PLAYERSLEEP);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (result == Player::NOT_POSSIBLE_NOW)
|
||||
{
|
||||
player->displayClientMessage(IDS_TILE_BED_NO_SLEEP);
|
||||
}
|
||||
else if (result == Player::NOT_SAFE)
|
||||
{
|
||||
player->displayClientMessage(IDS_TILE_BED_NOTSAFE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Icon *BedTile::getTexture(int face, int data)
|
||||
{
|
||||
if (face == Facing::DOWN)
|
||||
{
|
||||
return Tile::wood->getTexture(face);
|
||||
}
|
||||
|
||||
int direction = getDirection(data);
|
||||
int tileFacing = Direction::RELATIVE_DIRECTION_FACING[direction][face];
|
||||
|
||||
int part = isHeadPiece(data) ? PART_HEAD : PART_FOOT;
|
||||
|
||||
if ((part == PART_HEAD && tileFacing == Facing::NORTH) || (part == PART_FOOT && tileFacing == Facing::SOUTH))
|
||||
{
|
||||
return iconEnd[part];
|
||||
}
|
||||
if (tileFacing == Facing::EAST || tileFacing == Facing::WEST)
|
||||
{
|
||||
return iconSide[part];
|
||||
}
|
||||
return iconTop[part];
|
||||
}
|
||||
|
||||
void BedTile::registerIcons(IconRegister *iconRegister)
|
||||
{
|
||||
iconTop = new Icon *[2];
|
||||
iconTop[0] = iconRegister->registerIcon(L"bed_feet_top");
|
||||
iconTop[1] = iconRegister->registerIcon(L"bed_head_top");
|
||||
|
||||
iconEnd = new Icon *[2];
|
||||
iconEnd[0] = iconRegister->registerIcon(L"bed_feet_end");
|
||||
iconEnd[1] = iconRegister->registerIcon(L"bed_head_end");
|
||||
|
||||
iconSide = new Icon *[2];
|
||||
iconSide[0] = iconRegister->registerIcon(L"bed_feet_side");
|
||||
iconSide[1] = iconRegister->registerIcon(L"bed_head_side");
|
||||
}
|
||||
|
||||
int BedTile::getRenderShape()
|
||||
{
|
||||
return Tile::SHAPE_BED;
|
||||
}
|
||||
|
||||
bool BedTile::isCubeShaped()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BedTile::isSolidRender(bool isServerLevel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void BedTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr<TileEntity> forceEntity) // 4J added forceData, forceEntity param
|
||||
{
|
||||
setShape();
|
||||
}
|
||||
|
||||
void BedTile::neighborChanged(Level *level, int x, int y, int z, int type)
|
||||
{
|
||||
int data = level->getData(x, y, z);
|
||||
int direction = getDirection(data);
|
||||
|
||||
if (isHeadPiece(data))
|
||||
{
|
||||
if (level->getTile(x - HEAD_DIRECTION_OFFSETS[direction][0], y, z - HEAD_DIRECTION_OFFSETS[direction][1]) != id)
|
||||
{
|
||||
level->setTile(x, y, z, 0);
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (level->getTile(x + HEAD_DIRECTION_OFFSETS[direction][0], y, z + HEAD_DIRECTION_OFFSETS[direction][1]) != id)
|
||||
{
|
||||
level->setTile(x, y, z, 0);
|
||||
if (!level->isClientSide)
|
||||
{
|
||||
Tile::spawnResources(level, x, y, z, data, 0); // 4J - had to add Tile:: here for C++ since this class doesn't have this overloaded method itself
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int BedTile::getResource(int data, Random *random, int playerBonusLevel)
|
||||
{
|
||||
if (isHeadPiece(data))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return Item::bed->id;
|
||||
}
|
||||
|
||||
void BedTile::setShape()
|
||||
{
|
||||
Tile::setShape(0, 0, 0, 1, 9 / 16.0f, 1);
|
||||
}
|
||||
|
||||
bool BedTile::isHeadPiece(int data)
|
||||
{
|
||||
return (data & HEAD_PIECE_DATA) != 0;
|
||||
}
|
||||
|
||||
bool BedTile::isOccupied(int data)
|
||||
{
|
||||
return (data & OCCUPIED_DATA) != 0;
|
||||
}
|
||||
|
||||
void BedTile::setOccupied(Level *level, int x, int y, int z, bool occupied)
|
||||
{
|
||||
int data = level->getData(x, y, z);
|
||||
if (occupied)
|
||||
{
|
||||
data = data | OCCUPIED_DATA;
|
||||
} else
|
||||
{
|
||||
data = data & ~OCCUPIED_DATA;
|
||||
}
|
||||
level->setData(x, y, z, data);
|
||||
}
|
||||
|
||||
Pos *BedTile::findStandUpPosition(Level *level, int x, int y, int z, int skipCount)
|
||||
{
|
||||
int data = level->getData(x, y, z);
|
||||
int direction = DirectionalTile::getDirection(data);
|
||||
|
||||
// try to find a clear location near the bed
|
||||
for (int step = 0; step <= 1; step++)
|
||||
{
|
||||
int startX = x - BedTile::HEAD_DIRECTION_OFFSETS[direction][0] * step - 1;
|
||||
int startZ = z - BedTile::HEAD_DIRECTION_OFFSETS[direction][1] * step - 1;
|
||||
int endX = startX + 2;
|
||||
int endZ = startZ + 2;
|
||||
|
||||
for (int standX = startX; standX <= endX; standX++)
|
||||
{
|
||||
for (int standZ = startZ; standZ <= endZ; standZ++)
|
||||
{
|
||||
// 4J Stu - Changed to check isSolidBlockingTile rather than isEmpty for the blocks that we wish to place the player
|
||||
// This allows the player to spawn in blocks with snow, grass etc
|
||||
if (level->isTopSolidBlocking(standX, y - 1, standZ) &&
|
||||
!level->isSolidBlockingTile(standX, y, standZ) &&
|
||||
!level->isSolidBlockingTile(standX, y + 1, standZ))
|
||||
{
|
||||
if (skipCount > 0) {
|
||||
skipCount--;
|
||||
continue;
|
||||
}
|
||||
return new Pos(standX, y, standZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void BedTile::spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus)
|
||||
{
|
||||
if (!isHeadPiece(data))
|
||||
{
|
||||
Tile::spawnResources(level, x, y, z, data, odds, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int BedTile::getPistonPushReaction()
|
||||
{
|
||||
return Material::PUSH_DESTROY;
|
||||
}
|
||||
|
||||
int BedTile::cloneTileId(Level *level, int x, int y, int z)
|
||||
{
|
||||
return Item::bed_Id;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include "DirectionalTile.h"
|
||||
|
||||
class Pos;
|
||||
class Player;
|
||||
class Random;
|
||||
class Level;
|
||||
|
||||
class BedTile : public DirectionalTile
|
||||
{
|
||||
private:
|
||||
static const int PART_FOOT = 0;
|
||||
static const int PART_HEAD = 1;
|
||||
|
||||
Icon **iconEnd;
|
||||
Icon **iconSide;
|
||||
Icon **iconTop;
|
||||
|
||||
public:
|
||||
static const int HEAD_PIECE_DATA = 0x8;
|
||||
static const int OCCUPIED_DATA = 0x4;
|
||||
|
||||
static int HEAD_DIRECTION_OFFSETS[4][2];
|
||||
|
||||
BedTile(int id);
|
||||
|
||||
virtual void updateDefaultShape();
|
||||
virtual bool TestUse(Level *level, int x, int y, int z, shared_ptr<Player> player);
|
||||
virtual bool use(Level *level, int x, int y, int z, shared_ptr<Player> player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param
|
||||
virtual Icon *getTexture(int face, int data);
|
||||
//@Override
|
||||
void registerIcons(IconRegister *iconRegister);
|
||||
virtual int getRenderShape();
|
||||
virtual bool isCubeShaped();
|
||||
virtual bool isSolidRender(bool isServerLevel = false);
|
||||
virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr<TileEntity> forceEntity = shared_ptr<TileEntity>()); // 4J added forceData, forceEntity param
|
||||
virtual void neighborChanged(Level *level, int x, int y, int z, int type);
|
||||
virtual int getResource(int data, Random *random,int playerBonusLevel);
|
||||
|
||||
private:
|
||||
using Tile::setShape;
|
||||
void setShape();
|
||||
|
||||
public:
|
||||
static bool isHeadPiece(int data);
|
||||
static bool isOccupied(int data);
|
||||
static void setOccupied(Level *level, int x, int y, int z, bool occupied);
|
||||
static Pos *findStandUpPosition(Level *level, int x, int y, int z, int skipCount);
|
||||
|
||||
virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus);
|
||||
virtual int getPistonPushReaction();
|
||||
virtual int cloneTileId(Level *level, int x, int y, int z);
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.entity.ai.control.h"
|
||||
#include "net.minecraft.world.entity.animal.h"
|
||||
#include "net.minecraft.world.entity.player.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "BegGoal.h"
|
||||
|
||||
BegGoal::BegGoal(Wolf *wolf, float lookDistance)
|
||||
{
|
||||
player = weak_ptr<Player>();
|
||||
lookTime = 0;
|
||||
|
||||
this->wolf = wolf;
|
||||
this->level = wolf->level;
|
||||
this->lookDistance = lookDistance;
|
||||
setRequiredControlFlags(Control::LookControlFlag);
|
||||
}
|
||||
|
||||
bool BegGoal::canUse()
|
||||
{
|
||||
player = weak_ptr<Player>(level->getNearestPlayer(wolf->shared_from_this(), lookDistance));
|
||||
if (player.lock() == NULL) return false;
|
||||
wolf->setDespawnProtected();
|
||||
return playerHoldingInteresting(player.lock());
|
||||
}
|
||||
|
||||
bool BegGoal::canContinueToUse()
|
||||
{
|
||||
if (player.lock() == NULL || !player.lock()->isAlive()) return false;
|
||||
if (wolf->distanceToSqr(player.lock()) > lookDistance * lookDistance) return false;
|
||||
wolf->setDespawnProtected();
|
||||
return lookTime > 0 && playerHoldingInteresting(player.lock());
|
||||
}
|
||||
|
||||
void BegGoal::start()
|
||||
{
|
||||
wolf->setIsInterested(true);
|
||||
lookTime = 40 + wolf->getRandom()->nextInt(40);
|
||||
}
|
||||
|
||||
void BegGoal::stop()
|
||||
{
|
||||
wolf->setIsInterested(false);
|
||||
player = weak_ptr<Player>();
|
||||
}
|
||||
|
||||
void BegGoal::tick()
|
||||
{
|
||||
wolf->getLookControl()->setLookAt(player.lock()->x, player.lock()->y + player.lock()->getHeadHeight(), player.lock()->z, 10, wolf->getMaxHeadXRot());
|
||||
--lookTime;
|
||||
}
|
||||
|
||||
bool BegGoal::playerHoldingInteresting(shared_ptr<Player> player)
|
||||
{
|
||||
shared_ptr<ItemInstance> item = player->inventory->getSelected();
|
||||
if (item == NULL) return false;
|
||||
if (!wolf->isTame() && item->id == Item::bone_Id) return true;
|
||||
return wolf->isFood(item);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "Goal.h"
|
||||
|
||||
class Wolf;
|
||||
|
||||
class BegGoal : public Goal
|
||||
{
|
||||
private:
|
||||
Wolf *wolf; // Owner of this goal
|
||||
weak_ptr<Player> player;
|
||||
Level *level;
|
||||
float lookDistance;
|
||||
int lookTime;
|
||||
|
||||
public:
|
||||
BegGoal(Wolf *wolf, float lookDistance);
|
||||
|
||||
virtual bool canUse();
|
||||
virtual bool canContinueToUse();
|
||||
virtual void start();
|
||||
virtual void stop();
|
||||
virtual void tick();
|
||||
|
||||
private:
|
||||
bool playerHoldingInteresting(shared_ptr<Player> player);
|
||||
|
||||
public:
|
||||
// 4J Added override to update ai elements when loading entity from schematics
|
||||
virtual void setLevel(Level *level) { this->level = level; }
|
||||
};
|
||||
@@ -0,0 +1,188 @@
|
||||
#include "stdafx.h"
|
||||
#include "Node.h"
|
||||
#include "System.h"
|
||||
#include "BasicTypeContainers.h"
|
||||
#include "BinaryHeap.h"
|
||||
|
||||
// 4J Jev, add common ctor code.
|
||||
void BinaryHeap::_init()
|
||||
{
|
||||
heap = NodeArray(1024);
|
||||
sizeVar = 0;
|
||||
}
|
||||
|
||||
BinaryHeap::BinaryHeap()
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
BinaryHeap::~BinaryHeap()
|
||||
{
|
||||
delete[] heap.data;
|
||||
}
|
||||
|
||||
Node *BinaryHeap::insert(Node *node)
|
||||
{
|
||||
/* if (node->heapIdx >=0) throw new IllegalStateException("OW KNOWS!"); 4J Jev, removed try/catch */
|
||||
|
||||
// Expand if necessary.
|
||||
if (sizeVar == heap.length)
|
||||
{
|
||||
NodeArray newHeap = NodeArray(sizeVar << 1);
|
||||
|
||||
System::arraycopy(heap, 0, &newHeap, 0, sizeVar);
|
||||
|
||||
delete[] heap.data;
|
||||
heap = newHeap;
|
||||
}
|
||||
|
||||
// Insert at end and bubble up.
|
||||
heap[sizeVar] = node;
|
||||
node->heapIdx = sizeVar;
|
||||
upHeap(sizeVar++);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void BinaryHeap::clear()
|
||||
{
|
||||
sizeVar = 0;
|
||||
}
|
||||
|
||||
Node *BinaryHeap::peek()
|
||||
{
|
||||
return heap[0];
|
||||
}
|
||||
|
||||
Node *BinaryHeap::pop()
|
||||
{
|
||||
Node *popped = heap[0];
|
||||
heap[0] = heap[--sizeVar];
|
||||
heap[sizeVar] = NULL;
|
||||
if (sizeVar > 0) downHeap(0);
|
||||
popped->heapIdx=-1;
|
||||
return popped;
|
||||
}
|
||||
|
||||
void BinaryHeap::remove(Node *node)
|
||||
{
|
||||
// This is what node.heapIdx is for.
|
||||
heap[node->heapIdx] = heap[--sizeVar];
|
||||
heap[sizeVar] = NULL;
|
||||
if (sizeVar > node->heapIdx)
|
||||
{
|
||||
if (heap[node->heapIdx]->f < node->f)
|
||||
{
|
||||
upHeap(node->heapIdx);
|
||||
}
|
||||
else
|
||||
{
|
||||
downHeap(node->heapIdx);
|
||||
}
|
||||
}
|
||||
// Just as a precaution: should make stuff blow up if the node is abused.
|
||||
node->heapIdx = -1;
|
||||
}
|
||||
|
||||
void BinaryHeap::changeCost(Node *node, float newCost)
|
||||
{
|
||||
float oldCost = node->f;
|
||||
node->f = newCost;
|
||||
if (newCost < oldCost)
|
||||
{
|
||||
upHeap(node->heapIdx);
|
||||
}
|
||||
else
|
||||
{
|
||||
downHeap(node->heapIdx);
|
||||
}
|
||||
}
|
||||
|
||||
int BinaryHeap::size()
|
||||
{
|
||||
return sizeVar;
|
||||
}
|
||||
|
||||
void BinaryHeap::upHeap(int idx)
|
||||
{
|
||||
Node *node = heap[idx];
|
||||
float cost = node->f;
|
||||
while (idx > 0)
|
||||
{
|
||||
int parentIdx = (idx - 1) >> 1;
|
||||
Node *parent = heap[parentIdx];
|
||||
if (cost < parent->f)
|
||||
{
|
||||
heap[idx] = parent;
|
||||
parent->heapIdx = idx;
|
||||
idx = parentIdx;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
heap[idx] = node;
|
||||
node->heapIdx = idx;
|
||||
}
|
||||
|
||||
void BinaryHeap::downHeap(int idx)
|
||||
{
|
||||
Node *node = heap[idx];
|
||||
float cost = node->f;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int leftIdx = 1 + (idx << 1);
|
||||
int rightIdx = leftIdx + 1;
|
||||
|
||||
if (leftIdx >= sizeVar) break;
|
||||
|
||||
// We definitely have a left child.
|
||||
Node *leftNode = heap[leftIdx];
|
||||
float leftCost = leftNode->f;
|
||||
// We may have a right child.
|
||||
Node *rightNode;
|
||||
float rightCost;
|
||||
|
||||
if (rightIdx >= sizeVar)
|
||||
{
|
||||
// Only need to compare with left.
|
||||
rightNode = NULL;
|
||||
rightCost = Float::POSITIVE_INFINITY;
|
||||
}
|
||||
else
|
||||
{
|
||||
rightNode = heap[rightIdx];
|
||||
rightCost = rightNode->f;
|
||||
}
|
||||
|
||||
// Find the smallest of the three costs: the corresponding node
|
||||
// should be the parent.
|
||||
if (leftCost < rightCost)
|
||||
{
|
||||
if (leftCost < cost)
|
||||
{
|
||||
heap[idx] = leftNode;
|
||||
leftNode->heapIdx = idx;
|
||||
idx = leftIdx;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rightCost < cost)
|
||||
{
|
||||
heap[idx] = rightNode;
|
||||
rightNode->heapIdx = idx;
|
||||
idx = rightIdx;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
heap[idx] = node;
|
||||
node->heapIdx = idx;
|
||||
}
|
||||
|
||||
bool BinaryHeap::isEmpty()
|
||||
{
|
||||
return sizeVar==0;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Node.h"
|
||||
#include "System.h"
|
||||
#include "BasicTypeContainers.h"
|
||||
|
||||
class BinaryHeap
|
||||
{
|
||||
private:
|
||||
NodeArray heap;
|
||||
int sizeVar;
|
||||
|
||||
// 4J Jev, add common ctor code.
|
||||
void _init();
|
||||
|
||||
public:
|
||||
BinaryHeap();
|
||||
~BinaryHeap();
|
||||
|
||||
Node *insert(Node *node);
|
||||
void clear();
|
||||
Node *peek();
|
||||
Node *pop();
|
||||
void remove(Node *node);
|
||||
void changeCost(Node *node, float newCost);
|
||||
int size();
|
||||
|
||||
private:
|
||||
void upHeap(int idx);
|
||||
void downHeap(int idx);
|
||||
|
||||
public:
|
||||
bool isEmpty();
|
||||
};
|
||||
@@ -0,0 +1,308 @@
|
||||
#include "stdafx.h"
|
||||
#include "Color.h"
|
||||
#include "..\Minecraft.Client\Minecraft.h"
|
||||
#include "net.minecraft.world.level.levelgen.feature.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.entity.animal.h"
|
||||
#include "net.minecraft.world.entity.monster.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "Biome.h"
|
||||
#include "net.minecraft.world.level.biome.h"
|
||||
|
||||
//public static final Biome[] biomes = new Biome[256];
|
||||
Biome *Biome::biomes[256];
|
||||
|
||||
Biome *Biome::ocean = NULL;
|
||||
Biome *Biome::plains = NULL;
|
||||
Biome *Biome::desert = NULL;
|
||||
|
||||
Biome *Biome::extremeHills = NULL;
|
||||
Biome *Biome::forest = NULL;
|
||||
Biome *Biome::taiga = NULL;
|
||||
|
||||
Biome *Biome::swampland = NULL;
|
||||
Biome *Biome::river = NULL;
|
||||
|
||||
Biome *Biome::hell = NULL;
|
||||
Biome *Biome::sky = NULL;
|
||||
|
||||
Biome *Biome::frozenOcean = NULL;
|
||||
Biome *Biome::frozenRiver = NULL;
|
||||
Biome *Biome::iceFlats = NULL;
|
||||
Biome *Biome::iceMountains = NULL;
|
||||
Biome *Biome::mushroomIsland = NULL;
|
||||
Biome *Biome::mushroomIslandShore = NULL;
|
||||
Biome *Biome::beaches = NULL;
|
||||
Biome *Biome::desertHills = NULL;
|
||||
Biome *Biome::forestHills = NULL;
|
||||
Biome *Biome::taigaHills = NULL;
|
||||
Biome *Biome::smallerExtremeHills = NULL;
|
||||
|
||||
Biome *Biome::jungle = NULL;
|
||||
Biome *Biome::jungleHills = NULL;
|
||||
|
||||
|
||||
void Biome::staticCtor()
|
||||
{
|
||||
//public static final Biome[] biomes = new Biome[256];
|
||||
|
||||
Biome::ocean = (new OceanBiome(0))->setColor(0x000070)->setName(L"Ocean")->setDepthAndScale(-1, 0.4f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Ocean, eMinecraftColour_Foliage_Ocean, eMinecraftColour_Water_Ocean,eMinecraftColour_Sky_Ocean);
|
||||
Biome::plains = (new PlainsBiome(1))->setColor(0x8db360)->setName(L"Plains")->setTemperatureAndDownfall(0.8f, 0.4f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Plains, eMinecraftColour_Foliage_Plains, eMinecraftColour_Water_Plains,eMinecraftColour_Sky_Plains);
|
||||
Biome::desert = (new DesertBiome(2))->setColor(0xFA9418)->setName(L"Desert")->setNoRain()->setTemperatureAndDownfall(2, 0)->setDepthAndScale(0.1f, 0.2f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Desert, eMinecraftColour_Foliage_Desert, eMinecraftColour_Water_Desert,eMinecraftColour_Sky_Desert);
|
||||
|
||||
Biome::extremeHills = (new ExtremeHillsBiome(3))->setColor(0x606060)->setName(L"Extreme Hills")->setDepthAndScale(0.3f, 1.5f)->setTemperatureAndDownfall(0.2f, 0.3f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_ExtremeHills, eMinecraftColour_Foliage_ExtremeHills, eMinecraftColour_Water_ExtremeHills,eMinecraftColour_Sky_ExtremeHills);
|
||||
Biome::forest = (new ForestBiome(4))->setColor(0x056621)->setName(L"Forest")->setLeafColor(0x4EBA31)->setTemperatureAndDownfall(0.7f, 0.8f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Forest, eMinecraftColour_Foliage_Forest, eMinecraftColour_Water_Forest,eMinecraftColour_Sky_Forest);
|
||||
// 4J - brought forward Taiga temperature change from 0.3f to 0.05f, from 1.2.3
|
||||
Biome::taiga = (new TaigaBiome(5))->setColor(0x0b6659)->setName(L"Taiga")->setLeafColor(0x4EBA31)->setSnowCovered()->setTemperatureAndDownfall(0.05f, 0.8f)->setDepthAndScale(0.1f, 0.4f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Taiga, eMinecraftColour_Foliage_Taiga, eMinecraftColour_Water_Taiga,eMinecraftColour_Sky_Taiga);
|
||||
|
||||
Biome::swampland = (new SwampBiome(6))->setColor(0x07F9B2)->setName(L"Swampland")->setLeafColor(0x8BAF48)->setDepthAndScale(-0.2f, 0.1f)->setTemperatureAndDownfall(0.8f, 0.9f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Swampland, eMinecraftColour_Foliage_Swampland, eMinecraftColour_Water_Swampland,eMinecraftColour_Sky_Swampland);
|
||||
Biome::river = (new RiverBiome(7))->setColor(0x0000ff)->setName(L"River")->setDepthAndScale(-0.5f, 0)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_River, eMinecraftColour_Foliage_River, eMinecraftColour_Water_River,eMinecraftColour_Sky_River);
|
||||
|
||||
Biome::hell = (new HellBiome(8))->setColor(0xff0000)->setName(L"Hell")->setNoRain()->setTemperatureAndDownfall(2, 0)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Hell, eMinecraftColour_Foliage_Hell, eMinecraftColour_Water_Hell,eMinecraftColour_Sky_Hell);
|
||||
Biome::sky = (new TheEndBiome(9))->setColor(0x8080ff)->setName(L"Sky")->setNoRain()->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Sky, eMinecraftColour_Foliage_Sky, eMinecraftColour_Water_Sky,eMinecraftColour_Sky_Sky);
|
||||
|
||||
Biome::frozenOcean = (new OceanBiome(10))->setColor(0x9090a0)->setName(L"FrozenOcean")->setSnowCovered()->setDepthAndScale(-1, 0.5f)->setTemperatureAndDownfall(0, 0.5f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_FrozenOcean, eMinecraftColour_Foliage_FrozenOcean, eMinecraftColour_Water_FrozenOcean,eMinecraftColour_Sky_FrozenOcean);
|
||||
Biome::frozenRiver = (new RiverBiome(11))->setColor(0xa0a0ff)->setName(L"FrozenRiver")->setSnowCovered()->setDepthAndScale(-0.5f, 0)->setTemperatureAndDownfall(0, 0.5f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_FrozenRiver, eMinecraftColour_Foliage_FrozenRiver, eMinecraftColour_Water_FrozenRiver,eMinecraftColour_Sky_FrozenRiver);
|
||||
Biome::iceFlats = (new IceBiome(12))->setColor(0xffffff)->setName(L"Ice Plains")->setSnowCovered()->setTemperatureAndDownfall(0, 0.5f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_IcePlains, eMinecraftColour_Foliage_IcePlains, eMinecraftColour_Water_IcePlains,eMinecraftColour_Sky_IcePlains);
|
||||
Biome::iceMountains = (new IceBiome(13))->setColor(0xa0a0a0)->setName(L"Ice Mountains")->setSnowCovered()->setDepthAndScale(0.3f, 1.3f)->setTemperatureAndDownfall(0, 0.5f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_IceMountains, eMinecraftColour_Foliage_IceMountains, eMinecraftColour_Water_IceMountains,eMinecraftColour_Sky_IceMountains);
|
||||
|
||||
Biome::mushroomIsland = (new MushroomIslandBiome(14))->setColor(0xff00ff)->setName(L"MushroomIsland")->setTemperatureAndDownfall(0.9f, 1.0f)->setDepthAndScale(0.2f, 1.0f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_MushroomIsland, eMinecraftColour_Foliage_MushroomIsland, eMinecraftColour_Water_MushroomIsland,eMinecraftColour_Sky_MushroomIsland);
|
||||
Biome::mushroomIslandShore = (new MushroomIslandBiome(15))->setColor(0xa000ff)->setName(L"MushroomIslandShore")->setTemperatureAndDownfall(0.9f, 1.0f)->setDepthAndScale(-1, 0.1f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_MushroomIslandShore, eMinecraftColour_Foliage_MushroomIslandShore, eMinecraftColour_Water_MushroomIslandShore,eMinecraftColour_Sky_MushroomIslandShore);
|
||||
|
||||
Biome::beaches = (new BeachBiome(16))->setColor(0xfade55)->setName(L"Beach")->setTemperatureAndDownfall(0.8f, 0.4f)->setDepthAndScale(0.0f, 0.1f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Beach, eMinecraftColour_Foliage_Beach, eMinecraftColour_Water_Beach,eMinecraftColour_Sky_Beach);
|
||||
Biome::desertHills = (new DesertBiome(17))->setColor(0xd25f12)->setName(L"DesertHills")->setNoRain()->setTemperatureAndDownfall(2, 0)->setDepthAndScale(0.3f, 0.8f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_DesertHills, eMinecraftColour_Foliage_DesertHills, eMinecraftColour_Water_DesertHills,eMinecraftColour_Sky_DesertHills);
|
||||
Biome::forestHills = (new ForestBiome(18))->setColor(0x22551c)->setName(L"ForestHills")->setLeafColor(0x4EBA31)->setTemperatureAndDownfall(0.7f, 0.8f)->setDepthAndScale(0.3f, 0.7f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_ForestHills, eMinecraftColour_Foliage_ForestHills, eMinecraftColour_Water_ForestHills,eMinecraftColour_Sky_ForestHills);
|
||||
Biome::taigaHills = (new TaigaBiome(19))->setColor(0x163933)->setName(L"TaigaHills")->setSnowCovered()->setLeafColor(0x4EBA31)->setTemperatureAndDownfall(0.05f, 0.8f)->setDepthAndScale(0.3f, 0.8f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_TaigaHills, eMinecraftColour_Foliage_TaigaHills, eMinecraftColour_Water_TaigaHills,eMinecraftColour_Sky_TaigaHills);
|
||||
Biome::smallerExtremeHills = (new ExtremeHillsBiome(20))->setColor(0x72789a)->setName(L"Extreme Hills Edge")->setDepthAndScale(0.2f, 0.8f)->setTemperatureAndDownfall(0.2f, 0.3f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_ExtremeHillsEdge, eMinecraftColour_Foliage_ExtremeHillsEdge, eMinecraftColour_Water_ExtremeHillsEdge,eMinecraftColour_Sky_ExtremeHillsEdge);
|
||||
|
||||
Biome::jungle = (new JungleBiome(21))->setColor(0x537b09)->setName(L"Jungle")->setLeafColor(0x537b09)->setTemperatureAndDownfall(1.2f, 0.9f)->setDepthAndScale(0.2f, 0.4f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Jungle, eMinecraftColour_Foliage_Jungle, eMinecraftColour_Water_Jungle,eMinecraftColour_Sky_Jungle);
|
||||
Biome::jungleHills = (new JungleBiome(22))->setColor(0x2c4205)->setName(L"JungleHills")->setLeafColor(0x537b09)->setTemperatureAndDownfall(1.2f, 0.9f)->setDepthAndScale(1.8f, 0.5f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_JungleHills, eMinecraftColour_Foliage_JungleHills, eMinecraftColour_Water_JungleHills,eMinecraftColour_Sky_JungleHills);
|
||||
}
|
||||
|
||||
Biome::Biome(int id) : id(id)
|
||||
{
|
||||
// 4J Stu Default inits
|
||||
color = 0;
|
||||
// snowCovered = false; // 4J - this isn't set by the java game any more so removing to save confusion
|
||||
|
||||
topMaterial = (byte) Tile::grass_Id;
|
||||
material = (byte) Tile::dirt_Id;
|
||||
leafColor = 0x4EE031;
|
||||
_hasRain = true;
|
||||
depth = 0.1f;
|
||||
scale = 0.3f;
|
||||
temperature = 0.5f;
|
||||
downfall = 0.5f;
|
||||
//waterColor = 0xffffff; // 4J Stu - Not used
|
||||
decorator = NULL;
|
||||
|
||||
m_grassColor = eMinecraftColour_NOT_SET;
|
||||
m_foliageColor = eMinecraftColour_NOT_SET;
|
||||
m_waterColor = eMinecraftColour_NOT_SET;
|
||||
|
||||
/* 4J - removing these so that we can consistently return newly created trees via getTreeFeature, and let the calling function be resposible for deleting the returned tree
|
||||
normalTree = new TreeFeature();
|
||||
fancyTree = new BasicTree();
|
||||
birchTree = new BirchFeature();
|
||||
swampTree = new SwampTreeFeature();
|
||||
*/
|
||||
|
||||
biomes[id] = this;
|
||||
decorator = createDecorator();
|
||||
|
||||
friendlies.push_back(new MobSpawnerData(eTYPE_SHEEP, 12, 4, 4));
|
||||
friendlies.push_back(new MobSpawnerData(eTYPE_PIG, 10, 4, 4));
|
||||
friendlies_chicken.push_back(new MobSpawnerData(eTYPE_CHICKEN, 10, 4, 4)); // 4J - moved chickens to their own category
|
||||
friendlies.push_back(new MobSpawnerData(eTYPE_COW, 8, 4, 4));
|
||||
|
||||
enemies.push_back(new MobSpawnerData(eTYPE_SPIDER, 10, 4, 4));
|
||||
enemies.push_back(new MobSpawnerData(eTYPE_ZOMBIE, 10, 4, 4));
|
||||
enemies.push_back(new MobSpawnerData(eTYPE_SKELETON, 10, 4, 4));
|
||||
enemies.push_back(new MobSpawnerData(eTYPE_CREEPER, 10, 4, 4));
|
||||
enemies.push_back(new MobSpawnerData(eTYPE_SLIME, 10, 4, 4));
|
||||
enemies.push_back(new MobSpawnerData(eTYPE_ENDERMAN, 1, 1, 4));
|
||||
|
||||
// wolves are added to forests and taigas
|
||||
|
||||
waterFriendlies.push_back(new MobSpawnerData(eTYPE_SQUID, 10, 4, 4));
|
||||
}
|
||||
|
||||
Biome::~Biome()
|
||||
{
|
||||
if(decorator != NULL) delete decorator;
|
||||
}
|
||||
|
||||
BiomeDecorator *Biome::createDecorator()
|
||||
{
|
||||
return new BiomeDecorator(this);
|
||||
}
|
||||
|
||||
// 4J Added
|
||||
Biome *Biome::setLeafFoliageWaterSkyColor(eMinecraftColour grassColor, eMinecraftColour foliageColor, eMinecraftColour waterColour, eMinecraftColour skyColour)
|
||||
{
|
||||
m_grassColor = grassColor;
|
||||
m_foliageColor = foliageColor;
|
||||
m_waterColor = waterColour;
|
||||
m_skyColor = skyColour;
|
||||
return this;
|
||||
}
|
||||
|
||||
Biome *Biome::setTemperatureAndDownfall(float temp, float downfall)
|
||||
{
|
||||
this->temperature = temp;
|
||||
this->downfall = downfall;
|
||||
return this;
|
||||
}
|
||||
|
||||
Biome *Biome::setDepthAndScale(float depth, float scale)
|
||||
{
|
||||
this->depth = depth;
|
||||
this->scale = scale;
|
||||
return this;
|
||||
}
|
||||
|
||||
Biome *Biome::setNoRain()
|
||||
{
|
||||
_hasRain = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
Feature *Biome::getTreeFeature(Random *random)
|
||||
{
|
||||
if (random->nextInt(10) == 0)
|
||||
{
|
||||
return new BasicTree(false); // 4J used to return member fancyTree, now returning newly created object so that caller can be consistently resposible for cleanup
|
||||
}
|
||||
return new TreeFeature(false); // 4J used to return member normalTree, now returning newly created object so that caller can be consistently resposible for cleanup
|
||||
}
|
||||
|
||||
Feature *Biome::getGrassFeature(Random *random)
|
||||
{
|
||||
return new TallGrassFeature(Tile::tallgrass_Id, TallGrass::TALL_GRASS);
|
||||
}
|
||||
|
||||
Biome *Biome::setSnowCovered()
|
||||
{
|
||||
this->snowCovered = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
Biome *Biome::setName(const wstring &name)
|
||||
{
|
||||
this->m_name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
Biome *Biome::setLeafColor(int leafColor)
|
||||
{
|
||||
this->leafColor = leafColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
Biome *Biome::setColor(int color)
|
||||
{
|
||||
this->color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
int Biome::getSkyColor(float temp)
|
||||
{
|
||||
//temp /= 3.0f;
|
||||
//if (temp < -1) temp = -1;
|
||||
//if (temp > 1) temp = 1;
|
||||
//return Color::getHSBColor(224 / 360.0f - temp * 0.05f, 0.50f + temp * 0.1f, 1.0f).getRGB();
|
||||
|
||||
// 4J Stu - Load colour from texture pack
|
||||
return Minecraft::GetInstance()->getColourTable()->getColor( m_skyColor );
|
||||
}
|
||||
|
||||
vector<Biome::MobSpawnerData *> *Biome::getMobs(MobCategory *category)
|
||||
{
|
||||
if (category == MobCategory::monster) return &enemies;
|
||||
if (category == MobCategory::creature) return &friendlies;
|
||||
if (category == MobCategory::waterCreature) return &waterFriendlies;
|
||||
if (category == MobCategory::creature_chicken) return &friendlies_chicken;
|
||||
if (category == MobCategory::creature_wolf) return &friendlies_wolf;
|
||||
if (category == MobCategory::creature_mushroomcow) return &friendlies_mushroomcow;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Biome::hasSnow()
|
||||
{
|
||||
// 4J - snowCovered flag removed as it wasn't being set by the game anymore - snow is now temperature dependent to match code in rain rendering, shouldFreeze functions etc.
|
||||
if( !_hasRain ) return false;
|
||||
|
||||
if( getTemperature() >= 0.15f ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Biome::hasRain()
|
||||
{
|
||||
// 4J - snowCovered flag removed as it wasn't being set by the game anymore, replaced by call to hasSnow()
|
||||
if( hasSnow() ) return false;
|
||||
// if (snowCovered) return false;
|
||||
return _hasRain;
|
||||
}
|
||||
|
||||
bool Biome::isHumid()
|
||||
{
|
||||
return downfall > .85f;
|
||||
}
|
||||
|
||||
float Biome::getCreatureProbability()
|
||||
{
|
||||
return 0.1f;
|
||||
}
|
||||
|
||||
int Biome::getDownfallInt()
|
||||
{
|
||||
return (int) (downfall * 65536);
|
||||
}
|
||||
|
||||
int Biome::getTemperatureInt()
|
||||
{
|
||||
return (int) (temperature * 65536);
|
||||
}
|
||||
|
||||
// 4J - brought forward from 1.2.3
|
||||
float Biome::getDownfall()
|
||||
{
|
||||
return downfall;
|
||||
}
|
||||
|
||||
// 4J - brought forward from 1.2.3
|
||||
float Biome::getTemperature()
|
||||
{
|
||||
return temperature;
|
||||
}
|
||||
|
||||
void Biome::decorate(Level *level, Random *random, int xo, int zo)
|
||||
{
|
||||
decorator->decorate(level, random, xo, zo);
|
||||
}
|
||||
|
||||
int Biome::getGrassColor()
|
||||
{
|
||||
//double temp = Mth::clamp(getTemperature(), 0.0f, 1.0f);
|
||||
//double rain = Mth::clamp(getDownfall(), 0.0f, 1.0f);
|
||||
|
||||
//return GrassColor::get(temp, rain);
|
||||
return Minecraft::GetInstance()->getColourTable()->getColor( m_grassColor );
|
||||
}
|
||||
|
||||
int Biome::getFolageColor()
|
||||
{
|
||||
//double temp = Mth::clamp(getTemperature(), 0.0f, 1.0f);
|
||||
//double rain = Mth::clamp(getDownfall(), 0.0f, 1.0f);
|
||||
|
||||
//return FoliageColor::get(temp, rain);
|
||||
return Minecraft::GetInstance()->getColourTable()->getColor( m_foliageColor );
|
||||
}
|
||||
|
||||
// 4J Added
|
||||
int Biome::getWaterColor()
|
||||
{
|
||||
return Minecraft::GetInstance()->getColourTable()->getColor( m_waterColor );
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include "LevelSource.h"
|
||||
#include "Mob.h"
|
||||
#include "WeighedRandom.h"
|
||||
|
||||
class Feature;
|
||||
class MobCategory;
|
||||
class BiomeDecorator;
|
||||
class TreeFeature;
|
||||
class BasicTree;
|
||||
class BirchFeature;
|
||||
class SwampTreeFeature;
|
||||
class ChunkRebuildData;
|
||||
|
||||
class Biome
|
||||
{
|
||||
friend class ChunkRebuildData;
|
||||
public:
|
||||
// 4J JEV, replaces the static blocks.
|
||||
static void staticCtor();
|
||||
|
||||
static Biome *biomes[256];
|
||||
|
||||
static Biome *ocean;
|
||||
static Biome *plains;
|
||||
static Biome *desert;
|
||||
static Biome *extremeHills;
|
||||
static Biome *forest;
|
||||
static Biome *taiga;
|
||||
static Biome *swampland;
|
||||
static Biome *river;
|
||||
static Biome *hell;
|
||||
static Biome *sky;
|
||||
static Biome *frozenOcean;
|
||||
static Biome *frozenRiver;
|
||||
static Biome *iceFlats;
|
||||
static Biome *iceMountains;
|
||||
static Biome *mushroomIsland;
|
||||
static Biome *mushroomIslandShore ;
|
||||
static Biome *beaches;
|
||||
static Biome *desertHills;
|
||||
static Biome *forestHills;
|
||||
static Biome *taigaHills;
|
||||
static Biome *smallerExtremeHills;
|
||||
static Biome *jungle;
|
||||
static Biome *jungleHills;
|
||||
|
||||
static const int BIOME_COUNT = 23; // 4J Stu added
|
||||
|
||||
public:
|
||||
wstring m_name;
|
||||
int color;
|
||||
byte topMaterial;
|
||||
byte material;
|
||||
int leafColor;
|
||||
float depth;
|
||||
float scale;
|
||||
float temperature;
|
||||
float downfall;
|
||||
//int waterColor; // 4J Stu removed
|
||||
|
||||
BiomeDecorator *decorator;
|
||||
|
||||
const int id;
|
||||
|
||||
class MobSpawnerData : public WeighedRandomItem
|
||||
{
|
||||
public:
|
||||
eINSTANCEOF mobClass;
|
||||
int minCount;
|
||||
int maxCount;
|
||||
|
||||
MobSpawnerData(eINSTANCEOF mobClass, int probabilityWeight, int minCount, int maxCount) : WeighedRandomItem(probabilityWeight)
|
||||
{
|
||||
this->mobClass = mobClass;
|
||||
this->minCount = minCount;
|
||||
this->maxCount = maxCount;
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
vector<MobSpawnerData *> enemies;
|
||||
vector<MobSpawnerData *> friendlies;
|
||||
vector<MobSpawnerData *> waterFriendlies;
|
||||
vector<MobSpawnerData *> friendlies_chicken;
|
||||
vector<MobSpawnerData *> friendlies_wolf;
|
||||
vector<MobSpawnerData *> friendlies_mushroomcow;
|
||||
|
||||
Biome(int id);
|
||||
~Biome();
|
||||
|
||||
BiomeDecorator *createDecorator();
|
||||
|
||||
private:
|
||||
Biome *setTemperatureAndDownfall(float temp, float downfall);
|
||||
Biome *setDepthAndScale(float depth, float scale);
|
||||
|
||||
bool snowCovered;
|
||||
bool _hasRain;
|
||||
|
||||
// 4J Added
|
||||
eMinecraftColour m_grassColor;
|
||||
eMinecraftColour m_foliageColor;
|
||||
eMinecraftColour m_waterColor;
|
||||
eMinecraftColour m_skyColor;
|
||||
|
||||
Biome *setNoRain();
|
||||
|
||||
protected:
|
||||
/* removing these so that we can consistently return newly created trees via getTreeFeature, and let the calling function be resposible for deleting the returned tree
|
||||
TreeFeature *normalTree;
|
||||
BasicTree *fancyTree;
|
||||
BirchFeature *birchTree;
|
||||
SwampTreeFeature *swampTree;
|
||||
*/
|
||||
|
||||
public:
|
||||
virtual Feature *getTreeFeature(Random *random);
|
||||
virtual Feature *getGrassFeature(Random *random);
|
||||
|
||||
protected:
|
||||
Biome *setSnowCovered();
|
||||
Biome *setName(const wstring &name);
|
||||
Biome *setLeafColor(int leafColor);
|
||||
Biome *setColor(int color);
|
||||
|
||||
// 4J Added
|
||||
Biome *setLeafFoliageWaterSkyColor(eMinecraftColour grassColor, eMinecraftColour foliageColor, eMinecraftColour waterColour, eMinecraftColour skyColour);
|
||||
|
||||
public:
|
||||
virtual int getSkyColor(float temp);
|
||||
|
||||
vector<MobSpawnerData *> *getMobs(MobCategory *category);
|
||||
|
||||
virtual bool hasSnow();
|
||||
virtual bool hasRain();
|
||||
virtual bool isHumid();
|
||||
|
||||
virtual float getCreatureProbability();
|
||||
virtual int getDownfallInt();
|
||||
virtual int getTemperatureInt();
|
||||
virtual float getDownfall(); // 4J - brought forward from 1.2.3
|
||||
virtual float getTemperature(); // 4J - brought forward from 1.2.3
|
||||
|
||||
virtual void decorate(Level *level, Random *random, int xo, int zo);
|
||||
|
||||
virtual int getGrassColor();
|
||||
virtual int getFolageColor();
|
||||
virtual int getWaterColor(); // 4J Added
|
||||
};
|
||||
@@ -0,0 +1,165 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "Biome.h"
|
||||
#include "BiomeSource.h"
|
||||
#include "BiomeCache.h"
|
||||
#include "System.h"
|
||||
|
||||
BiomeCache::Block::Block(int x, int z, BiomeCache *parent)
|
||||
{
|
||||
// temps = floatArray(ZONE_SIZE * ZONE_SIZE, false); // MGH - added "no clear" flag to arrayWithLength
|
||||
// downfall = floatArray(ZONE_SIZE * ZONE_SIZE, false);
|
||||
// biomes = BiomeArray(ZONE_SIZE * ZONE_SIZE, false);
|
||||
biomeIndices = byteArray(ZONE_SIZE * ZONE_SIZE, false);
|
||||
|
||||
lastUse = 0;
|
||||
this->x = x;
|
||||
this->z = z;
|
||||
// parent->source->getTemperatureBlock(temps, x << ZONE_SIZE_BITS, z << ZONE_SIZE_BITS, ZONE_SIZE, ZONE_SIZE);
|
||||
// parent->source->getDownfallBlock(downfall, x << ZONE_SIZE_BITS, z << ZONE_SIZE_BITS, ZONE_SIZE, ZONE_SIZE);
|
||||
// parent->source->getBiomeBlock(biomes, x << ZONE_SIZE_BITS, z << ZONE_SIZE_BITS, ZONE_SIZE, ZONE_SIZE, false);
|
||||
parent->source->getBiomeIndexBlock(biomeIndices, x << ZONE_SIZE_BITS, z << ZONE_SIZE_BITS, ZONE_SIZE, ZONE_SIZE, false);
|
||||
|
||||
}
|
||||
|
||||
BiomeCache::Block::~Block()
|
||||
{
|
||||
// delete [] temps.data;
|
||||
// delete [] downfall.data;
|
||||
// delete [] biomes.data;
|
||||
delete [] biomeIndices.data;
|
||||
}
|
||||
|
||||
Biome *BiomeCache::Block::getBiome(int x, int z)
|
||||
{
|
||||
// return biomes[(x & ZONE_SIZE_MASK) | ((z & ZONE_SIZE_MASK) << ZONE_SIZE_BITS)];
|
||||
|
||||
int biomeIndex = biomeIndices[(x & ZONE_SIZE_MASK) | ((z & ZONE_SIZE_MASK) << ZONE_SIZE_BITS)];
|
||||
return Biome::biomes[biomeIndex];
|
||||
}
|
||||
|
||||
float BiomeCache::Block::getTemperature(int x, int z)
|
||||
{
|
||||
// return temps[(x & ZONE_SIZE_MASK) | ((z & ZONE_SIZE_MASK) << ZONE_SIZE_BITS)];
|
||||
|
||||
int biomeIndex = biomeIndices[(x & ZONE_SIZE_MASK) | ((z & ZONE_SIZE_MASK) << ZONE_SIZE_BITS)];
|
||||
return Biome::biomes[biomeIndex]->getTemperature();
|
||||
|
||||
}
|
||||
|
||||
float BiomeCache::Block::getDownfall(int x, int z)
|
||||
{
|
||||
// return downfall[(x & ZONE_SIZE_MASK) | ((z & ZONE_SIZE_MASK) << ZONE_SIZE_BITS)];
|
||||
|
||||
int biomeIndex = biomeIndices[(x & ZONE_SIZE_MASK) | ((z & ZONE_SIZE_MASK) << ZONE_SIZE_BITS)];
|
||||
return Biome::biomes[biomeIndex]->getDownfall();
|
||||
|
||||
}
|
||||
|
||||
BiomeCache::BiomeCache(BiomeSource *source)
|
||||
{
|
||||
// 4J Initialisors
|
||||
lastUpdateTime = 0;
|
||||
|
||||
this->source = source;
|
||||
|
||||
InitializeCriticalSection(&m_CS);
|
||||
|
||||
}
|
||||
|
||||
BiomeCache::~BiomeCache()
|
||||
{
|
||||
// 4J Stu - Delete source?
|
||||
// delete source;
|
||||
|
||||
for(AUTO_VAR(it, all.begin()); it != all.end(); ++it)
|
||||
{
|
||||
delete (*it);
|
||||
}
|
||||
DeleteCriticalSection(&m_CS);
|
||||
}
|
||||
|
||||
|
||||
BiomeCache::Block *BiomeCache::getBlockAt(int x, int z)
|
||||
{
|
||||
EnterCriticalSection(&m_CS);
|
||||
x >>= ZONE_SIZE_BITS;
|
||||
z >>= ZONE_SIZE_BITS;
|
||||
__int64 slot = (((__int64) x) & 0xffffffffl) | ((((__int64) z) & 0xffffffffl) << 32l);
|
||||
AUTO_VAR(it, cached.find(slot));
|
||||
Block *block = NULL;
|
||||
if (it == cached.end())
|
||||
{
|
||||
MemSect(48);
|
||||
block = new Block(x, z, this);
|
||||
cached[slot] = block;
|
||||
all.push_back(block);
|
||||
MemSect(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
block = it->second;
|
||||
}
|
||||
block->lastUse = app.getAppTime();
|
||||
LeaveCriticalSection(&m_CS);
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
Biome *BiomeCache::getBiome(int x, int z)
|
||||
{
|
||||
return getBlockAt(x, z)->getBiome(x, z);
|
||||
}
|
||||
|
||||
float BiomeCache::getTemperature(int x, int z)
|
||||
{
|
||||
return getBlockAt(x, z)->getTemperature(x, z);
|
||||
}
|
||||
|
||||
float BiomeCache::getDownfall(int x, int z)
|
||||
{
|
||||
return getBlockAt(x, z)->getDownfall(x, z);
|
||||
}
|
||||
|
||||
void BiomeCache::update()
|
||||
{
|
||||
EnterCriticalSection(&m_CS);
|
||||
__int64 now = app.getAppTime();
|
||||
__int64 utime = now - lastUpdateTime;
|
||||
if (utime > DECAY_TIME / 4 || utime < 0)
|
||||
{
|
||||
lastUpdateTime = now;
|
||||
|
||||
for (AUTO_VAR(it, all.begin()); it != all.end();)
|
||||
{
|
||||
Block *block = *it;
|
||||
__int64 time = now - block->lastUse;
|
||||
if (time > DECAY_TIME || time < 0)
|
||||
{
|
||||
it = all.erase(it);
|
||||
__int64 slot = (((__int64) block->x) & 0xffffffffl) | ((((__int64) block->z) & 0xffffffffl) << 32l);
|
||||
cached.erase(slot);
|
||||
delete block;
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&m_CS);
|
||||
}
|
||||
|
||||
BiomeArray BiomeCache::getBiomeBlockAt(int x, int z)
|
||||
{
|
||||
byteArray indices = getBlockAt(x, z)->biomeIndices;
|
||||
BiomeArray biomes(indices.length);
|
||||
for(int i=0;i<indices.length;i++)
|
||||
biomes[i] = Biome::biomes[indices[i]];
|
||||
return biomes;
|
||||
}
|
||||
|
||||
byteArray BiomeCache::getBiomeIndexBlockAt(int x, int z)
|
||||
{
|
||||
return getBlockAt(x, z)->biomeIndices;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
#include "..\Minecraft.World\JavaIntHash.h"
|
||||
|
||||
class BiomeCache
|
||||
{
|
||||
private:
|
||||
static const int DECAY_TIME = 1000 * 30;
|
||||
static const int ZONE_SIZE_BITS = 4;
|
||||
static const int ZONE_SIZE = 1 << ZONE_SIZE_BITS;
|
||||
static const int ZONE_SIZE_MASK = ZONE_SIZE - 1;
|
||||
|
||||
const BiomeSource *source;
|
||||
__int64 lastUpdateTime;
|
||||
|
||||
public:
|
||||
class Block
|
||||
{
|
||||
public:
|
||||
// MGH - changed this to just cache biome indices, as we have direct access to the data if we know the index.
|
||||
// floatArray temps;
|
||||
// floatArray downfall;
|
||||
// BiomeArray biomes;
|
||||
byteArray biomeIndices;
|
||||
int x, z;
|
||||
__int64 lastUse;
|
||||
|
||||
Block(int x, int z, BiomeCache *parent);
|
||||
~Block();
|
||||
Biome *getBiome(int x, int z);
|
||||
float getTemperature(int x, int z);
|
||||
float getDownfall(int x, int z);
|
||||
};
|
||||
|
||||
private:
|
||||
unordered_map<__int64,Block *,LongKeyHash,LongKeyEq> cached; // 4J - was LongHashMap
|
||||
vector<Block *> all; // was ArrayList<Block>
|
||||
|
||||
public:
|
||||
BiomeCache(BiomeSource *source);
|
||||
~BiomeCache();
|
||||
|
||||
Block *getBlockAt(int x, int z);
|
||||
Biome *getBiome(int x, int z);
|
||||
float getTemperature(int x, int z);
|
||||
float getDownfall(int x, int z);
|
||||
void update();
|
||||
BiomeArray getBiomeBlockAt(int x, int z);
|
||||
byteArray getBiomeIndexBlockAt(int x, int z);
|
||||
|
||||
private:
|
||||
CRITICAL_SECTION m_CS;
|
||||
};
|
||||
@@ -0,0 +1,328 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "net.minecraft.world.level.levelgen.feature.h"
|
||||
#include "net.minecraft.world.level.biome.h"
|
||||
|
||||
BiomeDecorator::BiomeDecorator(Biome *biome)
|
||||
{
|
||||
_init();
|
||||
|
||||
// 4J inits
|
||||
level = NULL;
|
||||
random = NULL;
|
||||
xo = 0;
|
||||
zo = 0;
|
||||
|
||||
this->biome = biome;
|
||||
}
|
||||
|
||||
void BiomeDecorator::decorate(Level *level, Random *random, int xo, int zo)
|
||||
{
|
||||
if (this->level != NULL)
|
||||
{
|
||||
app.DebugPrintf("BiomeDecorator::decorate - Already decorating!!\n");
|
||||
#ifndef _CONTENT_PACKAGE
|
||||
__debugbreak();
|
||||
//throw new RuntimeException("Already decorating!!");
|
||||
#endif
|
||||
}
|
||||
this->level = level;
|
||||
this->random = random;
|
||||
this->xo = xo;
|
||||
this->zo = zo;
|
||||
|
||||
decorate();
|
||||
|
||||
this->level = NULL;
|
||||
this->random = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void BiomeDecorator::_init()
|
||||
{
|
||||
clayFeature = new ClayFeature(4);
|
||||
sandFeature = new SandFeature(7, Tile::sand_Id);
|
||||
gravelFeature = new SandFeature(6, Tile::gravel_Id);
|
||||
dirtOreFeature = new OreFeature(Tile::dirt_Id, 32);
|
||||
gravelOreFeature = new OreFeature(Tile::gravel_Id, 32);
|
||||
coalOreFeature = new OreFeature(Tile::coalOre_Id, 16);
|
||||
ironOreFeature = new OreFeature(Tile::ironOre_Id, 8);
|
||||
goldOreFeature = new OreFeature(Tile::goldOre_Id, 8);
|
||||
redStoneOreFeature = new OreFeature(Tile::redStoneOre_Id, 7);
|
||||
diamondOreFeature = new OreFeature(Tile::diamondOre_Id, 7);
|
||||
lapisOreFeature = new OreFeature(Tile::lapisOre_Id, 6);
|
||||
yellowFlowerFeature = new FlowerFeature(Tile::flower_Id);
|
||||
roseFlowerFeature = new FlowerFeature(Tile::rose_Id);
|
||||
brownMushroomFeature = new FlowerFeature(Tile::mushroom1_Id);
|
||||
redMushroomFeature = new FlowerFeature(Tile::mushroom2_Id);
|
||||
hugeMushroomFeature = new HugeMushroomFeature();
|
||||
reedsFeature = new ReedsFeature();
|
||||
cactusFeature = new CactusFeature();
|
||||
waterlilyFeature = new WaterlilyFeature();
|
||||
|
||||
waterlilyCount = 0;
|
||||
treeCount = 0;
|
||||
flowerCount = 2;
|
||||
grassCount = 1;
|
||||
deadBushCount = 0;
|
||||
mushroomCount = 0;
|
||||
reedsCount = 0;
|
||||
cactusCount = 0;
|
||||
gravelCount = 1;
|
||||
sandCount = 3;
|
||||
clayCount = 1;
|
||||
hugeMushrooms = 0;
|
||||
liquids = true;
|
||||
}
|
||||
|
||||
|
||||
void BiomeDecorator::decorate()
|
||||
{
|
||||
PIXBeginNamedEvent(0,"Decorate ores");
|
||||
decorateOres();
|
||||
PIXEndNamedEvent();
|
||||
|
||||
PIXBeginNamedEvent(0,"Decorate sand/clay/gravel");
|
||||
for (int i = 0; i < sandCount; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
sandFeature->place(level, random, x, level->getTopSolidBlock(x, z), z);
|
||||
}
|
||||
|
||||
for (int i = 0; i < clayCount; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
clayFeature->place(level, random, x, level->getTopSolidBlock(x, z), z);
|
||||
}
|
||||
|
||||
for (int i = 0; i < gravelCount; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
sandFeature->place(level, random, x, level->getTopSolidBlock(x, z), z);
|
||||
}
|
||||
PIXEndNamedEvent();
|
||||
|
||||
PIXBeginNamedEvent(0, "Decorate forests");
|
||||
int forests = treeCount;
|
||||
if (random->nextInt(10) == 0) forests += 1;
|
||||
|
||||
for (int i = 0; i < forests; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
Feature *tree = biome->getTreeFeature(random);
|
||||
tree->init(1, 1, 1);
|
||||
tree->place(level, random, x, level->getHeightmap(x, z), z);
|
||||
delete tree;
|
||||
}
|
||||
PIXEndNamedEvent();
|
||||
|
||||
PIXBeginNamedEvent(0,"Decorate mushrooms/flowers/grass");
|
||||
for (int i = 0; i < hugeMushrooms; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
hugeMushroomFeature->place(level, random, x, level->getHeightmap(x, z), z);
|
||||
}
|
||||
|
||||
for (int i = 0; i < flowerCount; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(Level::genDepth);
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
yellowFlowerFeature->place(level, random, x, y, z);
|
||||
|
||||
if (random->nextInt(4) == 0)
|
||||
{
|
||||
x = xo + random->nextInt(16) + 8;
|
||||
y = random->nextInt(Level::genDepth);
|
||||
z = zo + random->nextInt(16) + 8;
|
||||
roseFlowerFeature->place(level, random, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < grassCount; i++)
|
||||
{
|
||||
//int grassType = TallGrass::TALL_GRASS;
|
||||
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(Level::genDepth);
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
MemSect(50);
|
||||
Feature *grassFeature = biome->getGrassFeature(random);
|
||||
MemSect(0);
|
||||
grassFeature->place(level, random, x, y, z);
|
||||
delete grassFeature;
|
||||
}
|
||||
PIXEndNamedEvent();
|
||||
PIXBeginNamedEvent(0,"Decorate bush/waterlily/mushroom/reeds/pumpkins/cactuses");
|
||||
|
||||
// 4J Stu - For some reason this was created each time round in the loop
|
||||
// I assume there is a case where deadBushCount could be 0
|
||||
DeadBushFeature *deadBushFeature = NULL;
|
||||
if(deadBushCount > 0) deadBushFeature = new DeadBushFeature(Tile::deadBush_Id);
|
||||
for (int i = 0; i < deadBushCount; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(Level::genDepth);
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
//new DeadBushFeature(Tile::deadBush_Id)->place(level, random, x, y, z);
|
||||
deadBushFeature->place(level, random, x, y, z);
|
||||
}
|
||||
if(deadBushFeature != NULL)delete deadBushFeature;
|
||||
|
||||
for (int i = 0; i < waterlilyCount; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(Level::genDepth);
|
||||
while (y > 0 && level->getTile(x, y - 1, z) == 0)
|
||||
y--;
|
||||
waterlilyFeature->place(level, random, x, y, z);
|
||||
}
|
||||
|
||||
for (int i = 0; i < mushroomCount; i++)
|
||||
{
|
||||
if (random->nextInt(4) == 0)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
int y = level->getHeightmap(x, z);
|
||||
brownMushroomFeature->place(level, random, x, y, z);
|
||||
}
|
||||
|
||||
if (random->nextInt(8) == 0)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(Level::genDepth);
|
||||
redMushroomFeature->place(level, random, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
if (random->nextInt(4) == 0)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(Level::genDepth);
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
brownMushroomFeature->place(level, random, x, y, z);
|
||||
}
|
||||
|
||||
if (random->nextInt(8) == 0)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(Level::genDepth);
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
redMushroomFeature->place(level, random, x, y, z);
|
||||
}
|
||||
|
||||
for (int i = 0; i < reedsCount; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(Level::genDepth);
|
||||
reedsFeature->place(level, random, x, y, z);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(Level::genDepth);
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
reedsFeature->place(level, random, x, y, z);
|
||||
}
|
||||
|
||||
if (random->nextInt(32) == 0)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(Level::genDepth);
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
PumpkinFeature *pumpkinFeature = new PumpkinFeature();
|
||||
pumpkinFeature->place(level, random, x, y, z);
|
||||
delete pumpkinFeature;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cactusCount; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(Level::genDepth);
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
cactusFeature->place(level, random, x, y, z);
|
||||
}
|
||||
|
||||
|
||||
PIXEndNamedEvent();
|
||||
PIXBeginNamedEvent(0,"Decorate liquids");
|
||||
|
||||
if( liquids )
|
||||
{
|
||||
// 4J Stu - For some reason this was created each time round in the loop
|
||||
SpringFeature *waterSpringFeature = new SpringFeature(Tile::water_Id);
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(random->nextInt(Level::genDepth - 8) + 8);
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
waterSpringFeature->place(level, random, x, y, z);
|
||||
}
|
||||
delete waterSpringFeature;
|
||||
|
||||
// 4J Stu - For some reason this was created each time round in the loop
|
||||
SpringFeature *lavaSpringFeature = new SpringFeature(Tile::lava_Id);
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16) + 8;
|
||||
int y = random->nextInt(random->nextInt(random->nextInt(Level::genDepth - 16) + 8) + 8);
|
||||
int z = zo + random->nextInt(16) + 8;
|
||||
lavaSpringFeature->place(level, random, x, y, z);
|
||||
}
|
||||
delete lavaSpringFeature;
|
||||
}
|
||||
PIXEndNamedEvent();
|
||||
}
|
||||
|
||||
void BiomeDecorator::decorate(int count, Feature *feature)
|
||||
{
|
||||
decorateDepthSpan(count, feature, 0, Level::genDepth);
|
||||
}
|
||||
|
||||
void BiomeDecorator::decorateDepthSpan(int count, Feature *feature, int y0, int y1)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16);
|
||||
int y = random->nextInt(y1 - y0) + y0;
|
||||
int z = zo + random->nextInt(16);
|
||||
feature->place(level, random, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
void BiomeDecorator::decorateDepthAverage(int count, Feature *feature, int yMid, int ySpan)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int x = xo + random->nextInt(16);
|
||||
int y = random->nextInt(ySpan) + random->nextInt(ySpan) + (yMid - ySpan);
|
||||
int z = zo + random->nextInt(16);
|
||||
feature->place(level, random, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
void BiomeDecorator::decorateOres()
|
||||
{
|
||||
level->setInstaTick(true); // 4J - optimisation
|
||||
decorateDepthSpan(20, dirtOreFeature, 0, Level::genDepth);
|
||||
decorateDepthSpan(10, gravelOreFeature, 0, Level::genDepth);
|
||||
decorateDepthSpan(20, coalOreFeature, 0, Level::genDepth);
|
||||
decorateDepthSpan(20, ironOreFeature, 0, Level::genDepth / 2);
|
||||
decorateDepthSpan(2, goldOreFeature, 0, Level::genDepth / 4);
|
||||
decorateDepthSpan(8, redStoneOreFeature, 0, Level::genDepth / 8);
|
||||
decorateDepthSpan(1, diamondOreFeature, 0, Level::genDepth / 8);
|
||||
decorateDepthAverage(1, lapisOreFeature, Level::genDepth / 8, Level::genDepth / 8);
|
||||
level->setInstaTick(false);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
class Level;
|
||||
class Random;
|
||||
class Biome;
|
||||
class Feature;
|
||||
|
||||
class BiomeDecorator
|
||||
{
|
||||
friend class DesertBiome;
|
||||
friend class ForestBiome;
|
||||
friend class PlainsBiome;
|
||||
friend class SwampBiome;
|
||||
friend class TaigaBiome;
|
||||
friend class MushroomIslandBiome;
|
||||
friend class BeachBiome;
|
||||
friend class JungleBiome;
|
||||
protected:
|
||||
Level *level;
|
||||
Random *random;
|
||||
int xo;
|
||||
int zo;
|
||||
Biome *biome;
|
||||
|
||||
public:
|
||||
BiomeDecorator(Biome *biome);
|
||||
|
||||
void decorate(Level *level, Random *random, int xo, int zo);
|
||||
|
||||
protected:
|
||||
Feature *clayFeature;
|
||||
Feature *sandFeature;
|
||||
Feature *gravelFeature;
|
||||
Feature *dirtOreFeature;
|
||||
Feature *gravelOreFeature;
|
||||
Feature *coalOreFeature;
|
||||
Feature *ironOreFeature;
|
||||
Feature *goldOreFeature;
|
||||
Feature *redStoneOreFeature;
|
||||
Feature *diamondOreFeature;
|
||||
Feature *lapisOreFeature;
|
||||
Feature *yellowFlowerFeature;
|
||||
Feature *roseFlowerFeature;
|
||||
Feature *brownMushroomFeature;
|
||||
Feature *redMushroomFeature;
|
||||
Feature *hugeMushroomFeature;
|
||||
Feature *reedsFeature;
|
||||
Feature *cactusFeature;
|
||||
Feature *waterlilyFeature;
|
||||
|
||||
int waterlilyCount;
|
||||
int treeCount;
|
||||
int flowerCount;
|
||||
int grassCount;
|
||||
int deadBushCount;
|
||||
int mushroomCount;
|
||||
int reedsCount;
|
||||
int cactusCount;
|
||||
int gravelCount;
|
||||
int sandCount;
|
||||
int clayCount;
|
||||
int hugeMushrooms;
|
||||
bool liquids;
|
||||
|
||||
void _init();
|
||||
|
||||
protected:
|
||||
virtual void decorate();
|
||||
|
||||
|
||||
void decorate(int count, Feature *feature);
|
||||
void decorateDepthSpan(int count, Feature *feature, int y0, int y1);
|
||||
void decorateDepthAverage(int count, Feature *feature, int yMid, int ySpan);
|
||||
void decorateOres();
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.biome.h"
|
||||
#include "net.minecraft.world.level.newbiome.layer.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "BiomeInitLayer.h"
|
||||
|
||||
BiomeInitLayer::BiomeInitLayer(__int64 seed, shared_ptr<Layer>parent, LevelType *levelType) : Layer(seed)
|
||||
{
|
||||
this->parent = parent;
|
||||
|
||||
|
||||
if(levelType == LevelType::lvl_normal_1_1)
|
||||
{
|
||||
startBiomes = BiomeArray(6);
|
||||
startBiomes[0] = Biome::desert;
|
||||
startBiomes[1] = Biome::forest;
|
||||
startBiomes[2] = Biome::extremeHills;
|
||||
startBiomes[3] = Biome::swampland;
|
||||
startBiomes[4] = Biome::plains;
|
||||
startBiomes[5] = Biome::taiga;
|
||||
}
|
||||
else
|
||||
{
|
||||
startBiomes = BiomeArray(7);
|
||||
startBiomes[0] = Biome::desert;
|
||||
startBiomes[1] = Biome::forest;
|
||||
startBiomes[2] = Biome::extremeHills;
|
||||
startBiomes[3] = Biome::swampland;
|
||||
startBiomes[4] = Biome::plains;
|
||||
startBiomes[5] = Biome::taiga;
|
||||
startBiomes[6] = Biome::jungle;
|
||||
}
|
||||
}
|
||||
|
||||
BiomeInitLayer::~BiomeInitLayer()
|
||||
{
|
||||
delete [] startBiomes.data;
|
||||
}
|
||||
|
||||
intArray BiomeInitLayer::getArea(int xo, int yo, int w, int h)
|
||||
{
|
||||
intArray b = parent->getArea(xo, yo, w, h);
|
||||
|
||||
intArray result = IntCache::allocate(w * h);
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
initRandom(x + xo, y + yo);
|
||||
int old = b[x + y * w];
|
||||
if (old == 0)
|
||||
{
|
||||
result[x + y * w] = 0;
|
||||
}
|
||||
else if (old == Biome::mushroomIsland->id)
|
||||
{
|
||||
result[x + y * w] = old;
|
||||
}
|
||||
else if (old == 1)
|
||||
{
|
||||
result[x + y * w] = startBiomes[nextRandom(startBiomes.length)]->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
int isTaiga = startBiomes[nextRandom(startBiomes.length)]->id;
|
||||
if (isTaiga == Biome::taiga->id)
|
||||
{
|
||||
result[x + y * w] = isTaiga;
|
||||
}
|
||||
else
|
||||
{
|
||||
result[x + y * w] = Biome::iceFlats->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "Layer.h"
|
||||
|
||||
class LevelType;
|
||||
|
||||
class BiomeInitLayer : public Layer
|
||||
{
|
||||
private:
|
||||
BiomeArray startBiomes;
|
||||
|
||||
public:
|
||||
BiomeInitLayer(__int64 seed, shared_ptr<Layer> parent, LevelType *levelType);
|
||||
virtual ~BiomeInitLayer();
|
||||
intArray getArea(int xo, int yo, int w, int h);
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.biome.h"
|
||||
#include "net.minecraft.world.level.newbiome.layer.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "BiomeOverrideLayer.h"
|
||||
|
||||
|
||||
BiomeOverrideLayer::BiomeOverrideLayer(int seedMixup) : Layer(seedMixup)
|
||||
{
|
||||
m_biomeOverride = byteArray( width * height );
|
||||
|
||||
#ifdef _UNICODE
|
||||
wstring path = L"GAME:\\GameRules\\biomemap.bin";
|
||||
HANDLE file = CreateFile(path.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
#else
|
||||
string path = "GAME:\\GameRules\\biomemap.bin";
|
||||
HANDLE file = CreateFile(path.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
#endif
|
||||
if( file == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
//assert(false);
|
||||
app.DebugPrintf("Biome override not found, using plains as default\n");
|
||||
|
||||
memset(m_biomeOverride.data,Biome::plains->id,m_biomeOverride.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
DWORD bytesRead,dwFileSize = GetFileSize(file,NULL);
|
||||
if(dwFileSize > m_biomeOverride.length)
|
||||
{
|
||||
app.DebugPrintf("Biomemap binary is too large!!\n");
|
||||
__debugbreak();
|
||||
}
|
||||
BOOL bSuccess = ReadFile(file,m_biomeOverride.data,dwFileSize,&bytesRead,NULL);
|
||||
|
||||
if(bSuccess==FALSE)
|
||||
{
|
||||
app.FatalLoadError();
|
||||
}
|
||||
|
||||
CloseHandle(file);
|
||||
}
|
||||
}
|
||||
|
||||
intArray BiomeOverrideLayer::getArea(int xo, int yo, int w, int h)
|
||||
{
|
||||
intArray result = IntCache::allocate(w * h);
|
||||
|
||||
int xOrigin = xo + width/2;
|
||||
int yOrigin = yo + height/2;
|
||||
if(xOrigin < 0 ) xOrigin = 0;
|
||||
if(xOrigin >= width) xOrigin = width - 1;
|
||||
if(yOrigin < 0 ) yOrigin = 0;
|
||||
if(yOrigin >= height) yOrigin = height - 1;
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
int curX = xOrigin + x;
|
||||
int curY = yOrigin + y;
|
||||
if(curX >= width) curX = width - 1;
|
||||
if(curY >= height) curY = height - 1;
|
||||
int index = curX + curY * width;
|
||||
|
||||
unsigned char headerValue = m_biomeOverride[index];
|
||||
result[x + y * w] = headerValue;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "Layer.h"
|
||||
|
||||
class LevelType;
|
||||
|
||||
class BiomeOverrideLayer : public Layer
|
||||
{
|
||||
private:
|
||||
static const unsigned int width = 216;
|
||||
static const unsigned int height = 216;
|
||||
|
||||
byteArray m_biomeOverride;
|
||||
|
||||
public:
|
||||
BiomeOverrideLayer(int seedMixup);
|
||||
intArray getArea(int xo, int yo, int w, int h);
|
||||
};
|
||||
@@ -0,0 +1,630 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.level.storage.h"
|
||||
#include "net.minecraft.world.level.biome.h"
|
||||
#include "net.minecraft.world.level.newbiome.layer.h"
|
||||
#include "System.h"
|
||||
#include "BiomeSource.h"
|
||||
#include "..\Minecraft.Client\Minecraft.h"
|
||||
#include "..\Minecraft.Client\ProgressRenderer.h"
|
||||
|
||||
// 4J - removal of separate temperature & downfall layers brought forward from 1.2.3
|
||||
void BiomeSource::_init()
|
||||
{
|
||||
layer = nullptr;
|
||||
zoomedLayer = nullptr;
|
||||
|
||||
cache = new BiomeCache(this);
|
||||
|
||||
playerSpawnBiomes.push_back(Biome::forest);
|
||||
playerSpawnBiomes.push_back(Biome::taiga);
|
||||
// 4J-PB - Moving forward plains as a spawnable biome (mainly for the Superflat world)
|
||||
playerSpawnBiomes.push_back(Biome::plains);
|
||||
playerSpawnBiomes.push_back(Biome::taigaHills);
|
||||
playerSpawnBiomes.push_back(Biome::forestHills);
|
||||
playerSpawnBiomes.push_back(Biome::jungle);
|
||||
playerSpawnBiomes.push_back(Biome::jungleHills);
|
||||
}
|
||||
|
||||
void BiomeSource::_init(__int64 seed, LevelType *generator)
|
||||
{
|
||||
_init();
|
||||
|
||||
LayerArray layers = Layer::getDefaultLayers(seed, generator);
|
||||
layer = layers[0];
|
||||
zoomedLayer = layers[1];
|
||||
|
||||
delete [] layers.data;
|
||||
}
|
||||
|
||||
BiomeSource::BiomeSource()
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
// 4J added
|
||||
BiomeSource::BiomeSource(__int64 seed, LevelType *generator)
|
||||
{
|
||||
_init(seed, generator);
|
||||
}
|
||||
|
||||
// 4J - removal of separate temperature & downfall layers brought forward from 1.2.3
|
||||
BiomeSource::BiomeSource(Level *level)
|
||||
{
|
||||
_init(level->getSeed(), level->getLevelData()->getGenerator());
|
||||
}
|
||||
|
||||
BiomeSource::~BiomeSource()
|
||||
{
|
||||
delete cache;
|
||||
}
|
||||
|
||||
Biome *BiomeSource::getBiome(ChunkPos *cp)
|
||||
{
|
||||
return getBiome(cp->x << 4, cp->z << 4);
|
||||
}
|
||||
|
||||
Biome *BiomeSource::getBiome(int x, int z)
|
||||
{
|
||||
return cache->getBiome(x, z);
|
||||
}
|
||||
|
||||
float BiomeSource::getDownfall(int x, int z) const
|
||||
{
|
||||
return cache->getDownfall(x, z);
|
||||
}
|
||||
|
||||
// 4J - note that caller is responsible for deleting returned array. temperatures array is for output only.
|
||||
floatArray BiomeSource::getDownfallBlock(int x, int z, int w, int h) const
|
||||
{
|
||||
floatArray downfalls;
|
||||
getDownfallBlock(downfalls, x, z, w, h);
|
||||
return downfalls;
|
||||
}
|
||||
|
||||
// 4J - note that caller is responsible for deleting returned array. temperatures array is for output only.
|
||||
// 4J - removal of separate temperature & downfall layers brought forward from 1.2.3
|
||||
void BiomeSource::getDownfallBlock(floatArray &downfalls, int x, int z, int w, int h) const
|
||||
{
|
||||
IntCache::releaseAll();
|
||||
//if (downfalls == NULL || downfalls->length < w * h)
|
||||
if (downfalls.data == NULL || downfalls.length < w * h)
|
||||
{
|
||||
if(downfalls.data != NULL) delete [] downfalls.data;
|
||||
downfalls = floatArray(w * h);
|
||||
}
|
||||
|
||||
intArray result = zoomedLayer->getArea(x, z, w, h);
|
||||
for (int i = 0; i < w * h; i++)
|
||||
{
|
||||
float d = (float) Biome::biomes[result[i]]->getDownfallInt() / 65536.0f;
|
||||
if (d > 1) d = 1;
|
||||
downfalls[i] = d;
|
||||
}
|
||||
}
|
||||
|
||||
BiomeCache::Block *BiomeSource::getBlockAt(int x, int y)
|
||||
{
|
||||
return cache->getBlockAt(x, y);
|
||||
}
|
||||
|
||||
float BiomeSource::getTemperature(int x, int y, int z) const
|
||||
{
|
||||
return scaleTemp(cache->getTemperature(x, z), y);
|
||||
}
|
||||
|
||||
// 4J - brought forward from 1.2.3
|
||||
float BiomeSource::scaleTemp(float temp, int y ) const
|
||||
{
|
||||
return temp;
|
||||
}
|
||||
|
||||
floatArray BiomeSource::getTemperatureBlock(int x, int z, int w, int h) const
|
||||
{
|
||||
floatArray temperatures;
|
||||
getTemperatureBlock(temperatures, x, z, w, h);
|
||||
return temperatures;
|
||||
}
|
||||
|
||||
// 4J - note that caller is responsible for deleting returned array. temperatures array is for output only.
|
||||
// 4J - removal of separate temperature & downfall layers brought forward from 1.2.3
|
||||
void BiomeSource::getTemperatureBlock(floatArray& temperatures, int x, int z, int w, int h) const
|
||||
{
|
||||
IntCache::releaseAll();
|
||||
//if (temperatures == null || temperatures.length < w * h) {
|
||||
if (temperatures.data == NULL || temperatures.length < w * h)
|
||||
{
|
||||
if( temperatures.data != NULL ) delete [] temperatures.data;
|
||||
temperatures = floatArray(w * h);
|
||||
}
|
||||
|
||||
intArray result = zoomedLayer->getArea(x, z, w, h);
|
||||
for (int i = 0; i < w * h; i++)
|
||||
{
|
||||
float t = (float) Biome::biomes[result[i]]->getTemperatureInt() / 65536.0f;
|
||||
if (t > 1) t = 1;
|
||||
temperatures[i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
BiomeArray BiomeSource::getRawBiomeBlock(int x, int z, int w, int h) const
|
||||
{
|
||||
BiomeArray biomes;
|
||||
getRawBiomeBlock(biomes, x, z, w, h);
|
||||
return biomes;
|
||||
}
|
||||
|
||||
// 4J added
|
||||
void BiomeSource::getRawBiomeIndices(intArray &biomes, int x, int z, int w, int h) const
|
||||
{
|
||||
IntCache::releaseAll();
|
||||
|
||||
intArray result = layer->getArea(x, z, w, h);
|
||||
for (int i = 0; i < w * h; i++)
|
||||
{
|
||||
biomes[i] = result[i];
|
||||
}
|
||||
}
|
||||
|
||||
void BiomeSource::getRawBiomeBlock(BiomeArray &biomes, int x, int z, int w, int h) const
|
||||
{
|
||||
IntCache::releaseAll();
|
||||
//if (biomes == null || biomes.length < w * h)
|
||||
if (biomes.data == NULL || biomes.length < w * h)
|
||||
{
|
||||
if(biomes.data != NULL) delete [] biomes.data;
|
||||
biomes = BiomeArray(w * h);
|
||||
}
|
||||
|
||||
intArray result = layer->getArea(x, z, w, h);
|
||||
for (int i = 0; i < w * h; i++)
|
||||
{
|
||||
biomes[i] = Biome::biomes[result[i]];
|
||||
#ifndef _CONTENT_PACKAGE
|
||||
if(biomes[i] == NULL)
|
||||
{
|
||||
app.DebugPrintf("Tried to assign null biome %d\n", result[i]);
|
||||
__debugbreak();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BiomeArray BiomeSource::getBiomeBlock(int x, int z, int w, int h) const
|
||||
{
|
||||
if (w == 16 && h == 16 && (x & 0xf) == 0 && (z & 0xf) == 0)
|
||||
{
|
||||
return cache->getBiomeBlockAt(x, z);
|
||||
}
|
||||
BiomeArray biomes;
|
||||
getBiomeBlock(biomes, x, z, w, h, true);
|
||||
return biomes;
|
||||
}
|
||||
|
||||
// 4J - caller is responsible for deleting biomes array
|
||||
void BiomeSource::getBiomeBlock(BiomeArray& biomes, int x, int z, int w, int h, bool useCache) const
|
||||
{
|
||||
IntCache::releaseAll();
|
||||
//if (biomes == null || biomes.length < w * h)
|
||||
if (biomes.data == NULL || biomes.length < w * h)
|
||||
{
|
||||
if(biomes.data != NULL) delete [] biomes.data;
|
||||
biomes = BiomeArray(w * h);
|
||||
}
|
||||
|
||||
if (useCache && w == 16 && h == 16 && (x & 0xf) == 0 && (z & 0xf) == 0)
|
||||
{
|
||||
BiomeArray tmp = cache->getBiomeBlockAt(x, z);
|
||||
System::arraycopy(tmp, 0, &biomes, 0, w * h);
|
||||
delete tmp.data; // MGH - added, the caching creates this array from the indices now.
|
||||
//return biomes;
|
||||
}
|
||||
|
||||
intArray result = zoomedLayer->getArea(x, z, w, h);
|
||||
for (int i = 0; i < w * h; i++)
|
||||
{
|
||||
biomes[i] = Biome::biomes[result[i]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
byteArray BiomeSource::getBiomeIndexBlock(int x, int z, int w, int h) const
|
||||
{
|
||||
if (w == 16 && h == 16 && (x & 0xf) == 0 && (z & 0xf) == 0)
|
||||
{
|
||||
return cache->getBiomeIndexBlockAt(x, z);
|
||||
}
|
||||
byteArray biomeIndices;
|
||||
getBiomeIndexBlock(biomeIndices, x, z, w, h, true);
|
||||
return biomeIndices;
|
||||
}
|
||||
|
||||
// 4J - caller is responsible for deleting biomes array
|
||||
void BiomeSource::getBiomeIndexBlock(byteArray& biomeIndices, int x, int z, int w, int h, bool useCache) const
|
||||
{
|
||||
IntCache::releaseAll();
|
||||
//if (biomes == null || biomes.length < w * h)
|
||||
if (biomeIndices.data == NULL || biomeIndices.length < w * h)
|
||||
{
|
||||
if(biomeIndices.data != NULL) delete [] biomeIndices.data;
|
||||
biomeIndices = byteArray(w * h);
|
||||
}
|
||||
|
||||
if (useCache && w == 16 && h == 16 && (x & 0xf) == 0 && (z & 0xf) == 0)
|
||||
{
|
||||
byteArray tmp = cache->getBiomeIndexBlockAt(x, z);
|
||||
System::arraycopy(tmp, 0, &biomeIndices, 0, w * h);
|
||||
//return biomes;
|
||||
}
|
||||
|
||||
intArray result = zoomedLayer->getArea(x, z, w, h);
|
||||
for (int i = 0; i < w * h; i++)
|
||||
{
|
||||
biomeIndices[i] = (byte)result[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an area around a block contains only the specified biomes.
|
||||
* Useful for placing elements like towns.
|
||||
*
|
||||
* This is a bit of a rough check, to make it as fast as possible. To ensure
|
||||
* NO other biomes, add a margin of at least four blocks to the radius
|
||||
*/
|
||||
bool BiomeSource::containsOnly(int x, int z, int r, vector<Biome *> allowed)
|
||||
{
|
||||
int x0 = ((x - r) >> 2);
|
||||
int z0 = ((z - r) >> 2);
|
||||
int x1 = ((x + r) >> 2);
|
||||
int z1 = ((z + r) >> 2);
|
||||
|
||||
int w = x1 - x0 + 1;
|
||||
int h = z1 - z0 + 1;
|
||||
|
||||
intArray biomes = layer->getArea(x0, z0, w, h);
|
||||
for (int i = 0; i < w * h; i++)
|
||||
{
|
||||
Biome *b = Biome::biomes[biomes[i]];
|
||||
if (find(allowed.begin(), allowed.end(), b) == allowed.end()) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an area around a block contains only the specified biome.
|
||||
* Useful for placing elements like towns.
|
||||
*
|
||||
* This is a bit of a rough check, to make it as fast as possible. To ensure
|
||||
* NO other biomes, add a margin of at least four blocks to the radius
|
||||
*/
|
||||
bool BiomeSource::containsOnly(int x, int z, int r, Biome *allowed)
|
||||
{
|
||||
int x0 = ((x - r) >> 2);
|
||||
int z0 = ((z - r) >> 2);
|
||||
int x1 = ((x + r) >> 2);
|
||||
int z1 = ((z + r) >> 2);
|
||||
|
||||
int w = x1 - x0;
|
||||
int h = z1 - z0;
|
||||
int biomesCount = w*h;
|
||||
intArray biomes = layer->getArea(x0, z0, w, h);
|
||||
for (unsigned int i = 0; i < biomesCount; i++)
|
||||
{
|
||||
Biome *b = Biome::biomes[biomes[i]];
|
||||
if (allowed != b) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the specified biome within the radius. This will return a random
|
||||
* position if several are found. This test is fairly rough.
|
||||
*
|
||||
* Returns null if the biome wasn't found
|
||||
*/
|
||||
TilePos *BiomeSource::findBiome(int x, int z, int r, Biome *toFind, Random *random)
|
||||
{
|
||||
int x0 = ((x - r) >> 2);
|
||||
int z0 = ((z - r) >> 2);
|
||||
int x1 = ((x + r) >> 2);
|
||||
int z1 = ((z + r) >> 2);
|
||||
|
||||
int w = x1 - x0 + 1;
|
||||
int h = z1 - z0 + 1;
|
||||
intArray biomes = layer->getArea(x0, z0, w, h);
|
||||
TilePos *res = NULL;
|
||||
int found = 0;
|
||||
int biomesCount = w*h;
|
||||
for (unsigned int i = 0; i < biomesCount; i++)
|
||||
{
|
||||
int xx = x0 + i % w;
|
||||
int zz = z0 + i / w;
|
||||
Biome *b = Biome::biomes[biomes[i]];
|
||||
if (b == toFind)
|
||||
{
|
||||
if (res == NULL || random->nextInt(found + 1) == 0)
|
||||
{
|
||||
res = new TilePos(xx, 0, zz);
|
||||
found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds one of the specified biomes within the radius. This will return a
|
||||
* random position if several are found. This test is fairly rough.
|
||||
*
|
||||
* Returns null if the biome wasn't found
|
||||
*/
|
||||
TilePos *BiomeSource::findBiome(int x, int z, int r, vector<Biome *> allowed, Random *random)
|
||||
{
|
||||
int x0 = ((x - r) >> 2);
|
||||
int z0 = ((z - r) >> 2);
|
||||
int x1 = ((x + r) >> 2);
|
||||
int z1 = ((z + r) >> 2);
|
||||
|
||||
int w = x1 - x0 + 1;
|
||||
int h = z1 - z0 + 1;
|
||||
MemSect(50);
|
||||
intArray biomes = layer->getArea(x0, z0, w, h);
|
||||
TilePos *res = NULL;
|
||||
int found = 0;
|
||||
int biomesCount = w*h;
|
||||
for (unsigned int i = 0; i < biomesCount; i++)
|
||||
{
|
||||
int xx = (x0 + i % w) << 2;
|
||||
int zz = (z0 + i / w) << 2;
|
||||
Biome *b = Biome::biomes[biomes[i]];
|
||||
if (find(allowed.begin(), allowed.end(), b) != allowed.end())
|
||||
{
|
||||
if (res == NULL || random->nextInt(found + 1) == 0)
|
||||
{
|
||||
delete res;
|
||||
res = new TilePos(xx, 0, zz);
|
||||
found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
MemSect(0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void BiomeSource::update()
|
||||
{
|
||||
cache->update();
|
||||
}
|
||||
|
||||
//#define DEBUG_SEEDS 50
|
||||
|
||||
// 4J added - find a seed for this biomesource that matches certain criteria
|
||||
__int64 BiomeSource::findSeed(LevelType *generator)
|
||||
{
|
||||
|
||||
__int64 bestSeed = 0;
|
||||
|
||||
ProgressRenderer *mcprogress = Minecraft::GetInstance()->progressRenderer;
|
||||
mcprogress->progressStage(IDS_PROGRESS_NEW_WORLD_SEED);
|
||||
|
||||
#ifndef _CONTENT_PACKAGE
|
||||
if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_EnableHeightWaterBiomeOverride))
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef DEBUG_SEEDS
|
||||
for( int k = 0; k < DEBUG_SEEDS; k++ )
|
||||
#endif
|
||||
{
|
||||
// Try and genuinely random this search up
|
||||
Random *pr = new Random(System::nanoTime());
|
||||
|
||||
// Raw biome data has one result per 4x4 group of tiles.
|
||||
// Removing a border of 8 from each side since we'll be doing special things at the edge to turn our world into an island, and so don't want to count things
|
||||
// in the edge region in case they later get removed
|
||||
static const int biomeWidth = ( 54 * 4 ) - 16; // Should be even so we can offset evenly
|
||||
static const int biomeOffset = -( biomeWidth / 2 );
|
||||
|
||||
// Storage for our biome indices
|
||||
intArray indices = intArray( biomeWidth * biomeWidth );
|
||||
|
||||
// Storage for the fractional amounts of each biome that will be calculated
|
||||
float toCompare[Biome::BIOME_COUNT];
|
||||
|
||||
bool matchFound = false;
|
||||
int tryCount = 0;
|
||||
|
||||
// Just keeping trying to generate seeds until we find one that matches our criteria
|
||||
do
|
||||
{
|
||||
__int64 seed = pr->nextLong();
|
||||
BiomeSource *biomeSource = new BiomeSource(seed,generator);
|
||||
|
||||
biomeSource->getRawBiomeIndices(indices, biomeOffset, biomeOffset, biomeWidth, biomeWidth);
|
||||
getFracs(indices, toCompare);
|
||||
|
||||
matchFound = getIsMatch( toCompare );
|
||||
|
||||
if( matchFound ) bestSeed = seed;
|
||||
|
||||
delete biomeSource;
|
||||
tryCount++;
|
||||
|
||||
mcprogress->progressStagePercentage( tryCount % 100 );
|
||||
} while (!matchFound);
|
||||
|
||||
// Clean up
|
||||
delete pr;
|
||||
delete indices.data;
|
||||
|
||||
#ifdef DEBUG_SEEDS
|
||||
app.DebugPrintf("%d: %d tries taken, seed used is %lld\n", k, tryCount, bestSeed);
|
||||
|
||||
BiomeSource *biomeSource = new BiomeSource(bestSeed);
|
||||
BiomeArray biomes = biomeSource->getBiomeBlock(-27 * 16, -27 * 16, 54 * 16, 54 * 16);
|
||||
|
||||
unsigned int *pixels = new unsigned int[54 * 16 * 54 * 16];
|
||||
for(int i = 0; i < 54 * 16 * 54 * 16; i++ )
|
||||
{
|
||||
int id = biomes[i]->id;
|
||||
|
||||
// Create following colours:
|
||||
// 0 ocean 0000 black
|
||||
// 1 plains 0001 pastel cyan
|
||||
// 2 desert 0010 green
|
||||
// 3 extreme hills 0011 yellow
|
||||
// 4 forest 0100 blue
|
||||
// 5 taiga 0101 magenta
|
||||
// 6 swamps 0110 cyan
|
||||
// 7 river 0111 white
|
||||
// 8 hell 1000 grey
|
||||
// 9 end biome 1001 white
|
||||
// 10 frozen ocean 1010 pastel green
|
||||
// 11 frozen river 1011 pastel yellow
|
||||
// 12 ice flats 1100 pastel blue
|
||||
// 13 ice mountains 1101 pastel magenta
|
||||
// 14 mushroom island 1110 red
|
||||
// 15 mushroom shore 1111 pastel red
|
||||
|
||||
if( id == 1 ) id = 14;
|
||||
else if ( id == 14 ) id = 1;
|
||||
else if( id == 9 ) id = 15;
|
||||
else if( id == 15 ) id = 9;
|
||||
pixels[i] = 0xff000000;
|
||||
if( id & 1 ) pixels[i] |= 0x00ff0000;
|
||||
if( id & 2 ) pixels[i] |= 0x0000ff00;
|
||||
if( id & 4 ) pixels[i] |= 0x000000ff;
|
||||
if( id & 8 ) pixels[i] |= 0x00808080;
|
||||
}
|
||||
D3DXIMAGE_INFO srcInfo;
|
||||
srcInfo.Format = D3DFMT_LIN_A8R8G8B8;
|
||||
srcInfo.ImageFileFormat = D3DXIFF_BMP;
|
||||
srcInfo.Width = 54 * 16;
|
||||
srcInfo.Height = 54 * 16;
|
||||
|
||||
char buf[256];
|
||||
sprintf(buf,"GAME:\\BiomeTest%d.bmp",k);
|
||||
RenderManager.SaveTextureData(buf, &srcInfo, (int *)pixels);
|
||||
|
||||
delete [] pixels;
|
||||
delete biomes.data;
|
||||
delete biomeSource;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return bestSeed;
|
||||
}
|
||||
|
||||
// 4J added - get the fractional amounts of each biome type in the given indices
|
||||
void BiomeSource::getFracs(intArray indices, float *fracs)
|
||||
{
|
||||
for( int i = 0; i < Biome::BIOME_COUNT; i++ )
|
||||
{
|
||||
fracs[i] = 0.0f;
|
||||
}
|
||||
|
||||
for( int i = 0; i < indices.length; i++ )
|
||||
{
|
||||
fracs[indices[i]] += 1.0f;
|
||||
}
|
||||
|
||||
for( int i = 0; i < Biome::BIOME_COUNT; i++ )
|
||||
{
|
||||
fracs[i] /= (float)(indices.length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 4J added - determine if this particular set of fractional amounts of biome types matches are requirements
|
||||
bool BiomeSource::getIsMatch(float *frac)
|
||||
{
|
||||
// A true for a particular biome type here marks it as one that *has* to be present
|
||||
static const bool critical[Biome::BIOME_COUNT] = {
|
||||
true, // ocean
|
||||
true, // plains
|
||||
true, // desert
|
||||
false, // extreme hills
|
||||
true, // forest
|
||||
true, // taiga
|
||||
true, // swamps
|
||||
false, // river
|
||||
false, // hell
|
||||
false, // end biome
|
||||
false, // frozen ocean
|
||||
false, // frozen river
|
||||
false, // ice flats
|
||||
false, // ice mountains
|
||||
true, // mushroom island / shore
|
||||
false, // mushroom shore (combined with above)
|
||||
false, // beach
|
||||
false, // desert hills (combined with desert)
|
||||
false, // forest hills (combined with forest)
|
||||
false, // taiga hills (combined with taga)
|
||||
false, // small extreme hills
|
||||
true, // jungle
|
||||
false, // jungle hills (combined with jungle)
|
||||
};
|
||||
|
||||
|
||||
// Don't want more than 15% ocean
|
||||
if( frac[0] > 0.15f )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Consider mushroom shore & islands as the same by finding max
|
||||
frac[14] = ( ( frac[15] > frac[14] ) ? frac[15] : frac[14] );
|
||||
|
||||
// Merge desert and desert hills
|
||||
frac[2] = ( ( frac[17] > frac[2] ) ? frac[17] : frac[2] );
|
||||
|
||||
// Merge forest and forest hills
|
||||
frac[4] = ( ( frac[18] > frac[4] ) ? frac[18] : frac[4] );
|
||||
|
||||
// Merge taiga and taiga hills
|
||||
frac[5] = ( ( frac[19] > frac[5] ) ? frac[19] : frac[5] );
|
||||
|
||||
// Merge jungle and jungle hills
|
||||
frac[21] = ( ( frac[22] > frac[21] ) ? frac[22] : frac[21] );
|
||||
|
||||
// Loop through all biome types, and:
|
||||
// (1) count them
|
||||
// (2) give up if one of the critical ones is missing
|
||||
|
||||
int typeCount = 0;
|
||||
for( int i = 0; i < Biome::BIOME_COUNT; i++ )
|
||||
{
|
||||
// We want to skip some where we have merged with another type
|
||||
if(i == 15 || i == 17 || i == 18 || i == 19 || i == 22) continue;
|
||||
|
||||
// Consider 0.1% as being "present" - this equates an area of about 3 chunks
|
||||
if( frac[i] > 0.001f )
|
||||
{
|
||||
typeCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If a critical biome is missing, just give up
|
||||
if( critical[i] )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Consider as suitable if we've got all the critical ones, and in total 9 or more - currently there's 8 critical so this just forces at least 1 more others
|
||||
return ( typeCount >= 9 );
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
#include "Biome.h"
|
||||
#include "BiomeSource.h"
|
||||
#include "BiomeCache.h"
|
||||
#include "net.minecraft.world.level.levelgen.synth.h"
|
||||
|
||||
class ChunkPos;
|
||||
class Level;
|
||||
class Layer;
|
||||
class TilePos;
|
||||
class LevelType;
|
||||
|
||||
class BiomeSource
|
||||
{
|
||||
private:
|
||||
shared_ptr<Layer> layer;
|
||||
shared_ptr<Layer> zoomedLayer;
|
||||
public:
|
||||
static const int CACHE_DIAMETER = 256;
|
||||
|
||||
private:
|
||||
BiomeCache *cache;
|
||||
|
||||
vector<Biome *> playerSpawnBiomes;
|
||||
|
||||
protected:
|
||||
void _init();
|
||||
void _init(__int64 seed, LevelType *generator);
|
||||
BiomeSource();
|
||||
|
||||
public:
|
||||
BiomeSource(__int64 seed, LevelType *generator);
|
||||
BiomeSource(Level *level);
|
||||
private:
|
||||
static bool getIsMatch(float *frac); // 4J added
|
||||
static void getFracs(intArray indices, float *fracs); // 4J added
|
||||
public:
|
||||
static __int64 findSeed(LevelType *generator); // 4J added
|
||||
~BiomeSource();
|
||||
|
||||
public:
|
||||
vector<Biome *> getPlayerSpawnBiomes() { return playerSpawnBiomes; }
|
||||
virtual Biome *getBiome(ChunkPos *cp);
|
||||
virtual Biome *getBiome(int x, int z);
|
||||
|
||||
// 4J - changed the interface for these methods, mainly for thread safety
|
||||
virtual float getDownfall(int x, int z) const;
|
||||
virtual floatArray getDownfallBlock(int x, int z, int w, int h) const;
|
||||
virtual void getDownfallBlock(floatArray &downfalls, int x, int z, int w, int h) const;
|
||||
|
||||
// 4J - changed the interface for these methods, mainly for thread safety
|
||||
virtual BiomeCache::Block *getBlockAt(int x, int y);
|
||||
virtual float getTemperature(int x, int y, int z) const;
|
||||
float scaleTemp(float temp, int y ) const; // 4J - brought forward from 1.2.3
|
||||
virtual floatArray getTemperatureBlock(int x, int z, int w, int h) const;
|
||||
virtual void getTemperatureBlock(floatArray& temperatures, int x, int z, int w, int h) const;
|
||||
|
||||
virtual BiomeArray getRawBiomeBlock(int x, int z, int w, int h) const;
|
||||
virtual void getRawBiomeBlock(BiomeArray &biomes, int x, int z, int w, int h) const;
|
||||
virtual void getRawBiomeIndices(intArray &biomes, int x, int z, int w, int h) const; // 4J added
|
||||
virtual BiomeArray getBiomeBlock(int x, int z, int w, int h) const;
|
||||
virtual void getBiomeBlock(BiomeArray& biomes, int x, int z, int w, int h, bool useCache) const;
|
||||
|
||||
virtual byteArray getBiomeIndexBlock(int x, int z, int w, int h) const;
|
||||
virtual void getBiomeIndexBlock(byteArray& biomeIndices, int x, int z, int w, int h, bool useCache) const;
|
||||
|
||||
/**
|
||||
* Checks if an area around a block contains only the specified biomes.
|
||||
* Useful for placing elements like towns.
|
||||
*
|
||||
* This is a bit of a rough check, to make it as fast as possible. To ensure
|
||||
* NO other biomes, add a margin of at least four blocks to the radius
|
||||
*/
|
||||
virtual bool containsOnly(int x, int z, int r, vector<Biome *> allowed);
|
||||
|
||||
/**
|
||||
* Checks if an area around a block contains only the specified biome.
|
||||
* Useful for placing elements like towns.
|
||||
*
|
||||
* This is a bit of a rough check, to make it as fast as possible. To ensure
|
||||
* NO other biomes, add a margin of at least four blocks to the radius
|
||||
*/
|
||||
virtual bool containsOnly(int x, int z, int r, Biome *allowed);
|
||||
|
||||
/**
|
||||
* Finds the specified biome within the radius. This will return a random
|
||||
* position if several are found. This test is fairly rough.
|
||||
*
|
||||
* Returns null if the biome wasn't found
|
||||
*/
|
||||
virtual TilePos *findBiome(int x, int z, int r, Biome *toFind, Random *random);
|
||||
|
||||
/**
|
||||
* Finds one of the specified biomes within the radius. This will return a
|
||||
* random position if several are found. This test is fairly rough.
|
||||
*
|
||||
* Returns null if the biome wasn't found
|
||||
*/
|
||||
virtual TilePos *findBiome(int x, int z, int r, vector<Biome *> allowed, Random *random);
|
||||
|
||||
void update();
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "BirchFeature.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
|
||||
BirchFeature::BirchFeature(bool doUpdate) : Feature(doUpdate)
|
||||
{
|
||||
}
|
||||
|
||||
bool BirchFeature::place(Level *level, Random *random, int x, int y, int z)
|
||||
{
|
||||
int treeHeight = random->nextInt(3) + 5;
|
||||
|
||||
bool free = true;
|
||||
if (y < 1 || y + treeHeight + 1 > Level::maxBuildHeight) return false;
|
||||
|
||||
for (int yy = y; yy <= y + 1 + treeHeight; yy++)
|
||||
{
|
||||
int r = 1;
|
||||
if (yy == y) r = 0;
|
||||
if (yy >= y + 1 + treeHeight - 2) r = 2;
|
||||
for (int xx = x - r; xx <= x + r && free; xx++)
|
||||
{
|
||||
for (int zz = z - r; zz <= z + r && free; zz++)
|
||||
{
|
||||
if (yy >= 0 && yy < Level::maxBuildHeight)
|
||||
{
|
||||
int tt = level->getTile(xx, yy, zz);
|
||||
if (tt != 0 && tt != Tile::leaves_Id) free = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
free = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!free) return false;
|
||||
|
||||
int belowTile = level->getTile(x, y - 1, z);
|
||||
if ((belowTile != Tile::grass_Id && belowTile != Tile::dirt_Id) || y >= Level::maxBuildHeight - treeHeight - 1) return false;
|
||||
|
||||
// 4J Stu Added to stop tree features generating areas previously place by game rule generation
|
||||
if(app.getLevelGenerationOptions() != NULL)
|
||||
{
|
||||
LevelGenerationOptions *levelGenOptions = app.getLevelGenerationOptions();
|
||||
int radius = 3;
|
||||
bool intersects = levelGenOptions->checkIntersects(x - radius, y - 1, z - radius, x + radius, y + treeHeight, z + radius);
|
||||
if(intersects)
|
||||
{
|
||||
//app.DebugPrintf("Skipping reeds feature generation as it overlaps a game rule structure\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
level->setTileNoUpdate(x, y - 1, z, Tile::dirt_Id);
|
||||
|
||||
for (int yy = y - 3 + treeHeight; yy <= y + treeHeight; yy++)
|
||||
{
|
||||
int yo = yy - (y + treeHeight);
|
||||
int offs = 1 - yo / 2;
|
||||
for (int xx = x - offs; xx <= x + offs; xx++)
|
||||
{
|
||||
int xo = xx - (x);
|
||||
for (int zz = z - offs; zz <= z + offs; zz++)
|
||||
{
|
||||
int zo = zz - (z);
|
||||
if (abs(xo) == offs && abs(zo) == offs && (random->nextInt(2) == 0 || yo == 0)) continue;
|
||||
if (!Tile::solid[level->getTile(xx, yy, zz)]) placeBlock(level, xx, yy, zz, Tile::leaves_Id, LeafTile::BIRCH_LEAF);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int hh = 0; hh < treeHeight; hh++)
|
||||
{
|
||||
int t = level->getTile(x, y + hh, z);
|
||||
if (t == 0 || t == Tile::leaves_Id) placeBlock(level, x, y + hh, z, Tile::treeTrunk_Id, TreeTile::BIRCH_TRUNK);
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "Feature.h"
|
||||
|
||||
class Level;
|
||||
|
||||
class BirchFeature : public Feature
|
||||
{
|
||||
public:
|
||||
BirchFeature(bool doUpdate);
|
||||
virtual bool place(Level *level, Random *random, int x, int y, int z);
|
||||
};
|
||||
@@ -0,0 +1,227 @@
|
||||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.damagesource.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.level.tile.h"
|
||||
#include "net.minecraft.world.phys.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "net.minecraft.world.entity.projectile.h"
|
||||
#include "SharedConstants.h"
|
||||
#include "..\Minecraft.Client\Textures.h"
|
||||
#include "Blaze.h"
|
||||
#include "SoundTypes.h"
|
||||
|
||||
|
||||
|
||||
Blaze::Blaze(Level *level) : Monster(level)
|
||||
{
|
||||
// 4J Stu - This function call had to be moved here from the Entity ctor to ensure that
|
||||
// the derived version of the function is called
|
||||
this->defineSynchedData();
|
||||
|
||||
// 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called
|
||||
health = getMaxHealth();
|
||||
|
||||
this->textureIdx = TN_MOB_BLAZE; // 4J Was "/mob/fire.png";
|
||||
|
||||
fireImmune = true;
|
||||
attackDamage = 6;
|
||||
xpReward = XP_REWARD_LARGE;
|
||||
// this.setSize(1.2f, 1.8f);
|
||||
|
||||
// 4J Default inits
|
||||
allowedHeightOffset = 0.5f;
|
||||
nextHeightOffsetChangeTick = 0;
|
||||
attackCounter = 0;
|
||||
}
|
||||
|
||||
int Blaze::getMaxHealth()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
void Blaze::defineSynchedData()
|
||||
{
|
||||
Monster::defineSynchedData();
|
||||
|
||||
entityData->define(DATA_FLAGS_ID, (byte) 0);
|
||||
}
|
||||
|
||||
int Blaze::getAmbientSound()
|
||||
{
|
||||
return eSoundType_MOB_BLAZE_BREATHE;
|
||||
}
|
||||
|
||||
int Blaze::getHurtSound()
|
||||
{
|
||||
return eSoundType_MOB_BLAZE_HURT;
|
||||
}
|
||||
|
||||
int Blaze::getDeathSound()
|
||||
{
|
||||
return eSoundType_MOB_BLAZE_DEATH;
|
||||
}
|
||||
|
||||
int Blaze::getLightColor(float a)
|
||||
{
|
||||
return SharedConstants::FULLBRIGHT_LIGHTVALUE;
|
||||
}
|
||||
|
||||
float Blaze::getBrightness(float a)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
void Blaze::aiStep()
|
||||
{
|
||||
if (!level->isClientSide)
|
||||
{
|
||||
|
||||
if (isInWaterOrRain())
|
||||
{
|
||||
hurt(DamageSource::drown, 1);
|
||||
}
|
||||
|
||||
nextHeightOffsetChangeTick--;
|
||||
if (nextHeightOffsetChangeTick <= 0)
|
||||
{
|
||||
nextHeightOffsetChangeTick = SharedConstants::TICKS_PER_SECOND * 5;
|
||||
allowedHeightOffset = .5f + (float) random->nextGaussian() * 3;
|
||||
}
|
||||
|
||||
if (getAttackTarget() != NULL && (getAttackTarget()->y + getAttackTarget()->getHeadHeight()) > (this->y + getHeadHeight() + allowedHeightOffset))
|
||||
{
|
||||
yd = yd + (.3f - yd) * .3f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (random->nextInt(24) == 0)
|
||||
{
|
||||
level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, eSoundType_FIRE_FIRE, 1 + random->nextFloat(), random->nextFloat() * 0.7f + 0.3f);
|
||||
}
|
||||
|
||||
// slow falling, like chicken
|
||||
if (!onGround && yd < 0)
|
||||
{
|
||||
yd *= 0.6;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
level->addParticle(eParticleType_largesmoke, x + (random->nextDouble() - 0.5) * bbWidth, y + random->nextDouble() * bbHeight, z + (random->nextDouble() - 0.5) * bbWidth, 0, 0, 0);
|
||||
}
|
||||
|
||||
Monster::aiStep();
|
||||
}
|
||||
|
||||
void Blaze::checkHurtTarget(shared_ptr<Entity> target, float d)
|
||||
{
|
||||
if (attackTime <= 0 && d < 2.0f && target->bb->y1 > bb->y0 && target->bb->y0 < bb->y1)
|
||||
{
|
||||
attackTime = 20;
|
||||
doHurtTarget(target);
|
||||
}
|
||||
else if (d < 30)
|
||||
{
|
||||
double xd = target->x - x;
|
||||
double yd = (target->bb->y0 + target->bbHeight / 2) - (y + bbHeight / 2);
|
||||
double zd = target->z - z;
|
||||
|
||||
if (attackTime == 0)
|
||||
{
|
||||
attackCounter++;
|
||||
if (attackCounter == 1)
|
||||
{
|
||||
attackTime = SharedConstants::TICKS_PER_SECOND * 3;
|
||||
setCharged(true);
|
||||
}
|
||||
else if (attackCounter <= 4)
|
||||
{
|
||||
attackTime = SharedConstants::TICKS_PER_SECOND / 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
attackTime = SharedConstants::TICKS_PER_SECOND * 5;
|
||||
attackCounter = 0;
|
||||
setCharged(false);
|
||||
}
|
||||
|
||||
if (attackCounter > 1)
|
||||
{
|
||||
float sqd = sqrt(d) * .5f;
|
||||
|
||||
level->levelEvent(nullptr, LevelEvent::SOUND_BLAZE_FIREBALL, (int) x, (int) y, (int) z, 0);
|
||||
// level.playSound(this, "mob.ghast.fireball", getSoundVolume(), (random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f);
|
||||
for (int i = 0; i < 1; i++) {
|
||||
shared_ptr<SmallFireball> ie = shared_ptr<SmallFireball>( new SmallFireball(level, dynamic_pointer_cast<Mob>( shared_from_this() ), xd + random->nextGaussian() * sqd, yd, zd + random->nextGaussian() * sqd) );
|
||||
// Vec3 v = getViewVector(1);
|
||||
// ie.x = x + v.x * 1.5;
|
||||
ie->y = y + bbHeight / 2 + 0.5f;
|
||||
// ie.z = z + v.z * 1.5;
|
||||
level->addEntity(ie);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
yRot = (float) (atan2(zd, xd) * 180 / PI) - 90;
|
||||
|
||||
holdGround = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Blaze::causeFallDamage(float distance)
|
||||
{
|
||||
}
|
||||
|
||||
int Blaze::getDeathLoot()
|
||||
{
|
||||
return Item::blazeRod_Id;
|
||||
}
|
||||
|
||||
bool Blaze::isOnFire()
|
||||
{
|
||||
return isCharged();
|
||||
}
|
||||
|
||||
void Blaze::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel)
|
||||
{
|
||||
if (wasKilledByPlayer)
|
||||
{
|
||||
int count = random->nextInt(2 + playerBonusLevel);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
spawnAtLocation(Item::blazeRod_Id, 1);
|
||||
}
|
||||
// 4J-PB - added to the XBLA version due to our limited amount of glowstone in the Nether - drop 0-2 glowstone dust
|
||||
count = random->nextInt(3 + playerBonusLevel);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
spawnAtLocation(Item::yellowDust_Id, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Blaze::isCharged()
|
||||
{
|
||||
return (entityData->getByte(DATA_FLAGS_ID) & 0x1) != 0;
|
||||
}
|
||||
|
||||
void Blaze::setCharged(bool value)
|
||||
{
|
||||
byte flags = entityData->getByte(DATA_FLAGS_ID);
|
||||
if (value)
|
||||
{
|
||||
flags |= 0x1;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags &= ~0x1;
|
||||
}
|
||||
entityData->set(DATA_FLAGS_ID, flags);
|
||||
}
|
||||
|
||||
bool Blaze::isDarkEnoughToSpawn()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "Monster.h"
|
||||
|
||||
class Blaze : public Monster
|
||||
{
|
||||
public:
|
||||
eINSTANCEOF GetType() { return eTYPE_BLAZE; }
|
||||
static Entity *create(Level *level) { return new Blaze(level); }
|
||||
|
||||
// private int nextBurnNeighborsTick;
|
||||
private:
|
||||
float allowedHeightOffset;
|
||||
int nextHeightOffsetChangeTick;
|
||||
int attackCounter;
|
||||
|
||||
static const int DATA_FLAGS_ID = 16;
|
||||
|
||||
public:
|
||||
Blaze(Level *level);
|
||||
virtual int getMaxHealth();
|
||||
|
||||
protected:
|
||||
virtual void defineSynchedData();
|
||||
virtual int getAmbientSound();
|
||||
virtual int getHurtSound();
|
||||
virtual int getDeathSound();
|
||||
|
||||
public:
|
||||
virtual int getLightColor(float a);
|
||||
virtual float getBrightness(float a);
|
||||
virtual void aiStep();
|
||||
|
||||
protected:
|
||||
virtual void checkHurtTarget(shared_ptr<Entity> target, float d);
|
||||
virtual void causeFallDamage(float distance);
|
||||
virtual int getDeathLoot();
|
||||
|
||||
public:
|
||||
virtual bool isOnFire();
|
||||
|
||||
protected:
|
||||
virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel);
|
||||
|
||||
public:
|
||||
bool isCharged();
|
||||
void setCharged(bool value);
|
||||
|
||||
protected:
|
||||
bool isDarkEnoughToSpawn();
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "stdafx.h"
|
||||
#include "BlockDestructionProgress.h"
|
||||
|
||||
BlockDestructionProgress::BlockDestructionProgress(int id, int x, int y, int z)
|
||||
{
|
||||
this->id = id;
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->z = z;
|
||||
|
||||
progress = 0;
|
||||
updatedRenderTick = 0;
|
||||
}
|
||||
|
||||
int BlockDestructionProgress::getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
int BlockDestructionProgress::getX()
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
int BlockDestructionProgress::getY()
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
int BlockDestructionProgress::getZ()
|
||||
{
|
||||
return z;
|
||||
}
|
||||
|
||||
void BlockDestructionProgress::setProgress(int progress)
|
||||
{
|
||||
if (progress > 10)
|
||||
{
|
||||
progress = 10;
|
||||
}
|
||||
this->progress = progress;
|
||||
}
|
||||
|
||||
int BlockDestructionProgress::getProgress()
|
||||
{
|
||||
return progress;
|
||||
}
|
||||
|
||||
void BlockDestructionProgress::updateTick(int tick)
|
||||
{
|
||||
this->updatedRenderTick = tick;
|
||||
}
|
||||
|
||||
int BlockDestructionProgress::getUpdatedRenderTick()
|
||||
{
|
||||
return updatedRenderTick;
|
||||
}
|
||||
Loaded 100 of 16345 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user