~melchizedek6809/WolkenWelten

6d229600f745dbd4bd087f01a5fc06f58422b0de — Ben (X13/Arch) 1 year, 7 months ago 19a5ae3
Alot of fixes, mostly regarding animals and UI
M client/src/game/animal.c => client/src/game/animal.c +6 -6
@@ 86,7 86,7 @@ static void animalDraw(animal *e){

void animalDrawAll(){
	shaderBind(sMesh);
	for(uint i=0;i<animalCount;i++){
	for(uint i=0;i<animalListMax;i++){
		if(animalDistance(&animalList[i],player) > ANIMAL_FADEOUT){
			animalList[i].screenPos = vecNOne();
			continue;


@@ 97,14 97,14 @@ void animalDrawAll(){

void animalSyncFromServer(const packet *p){
	const uint newC = p->v.u16[5];
	if(newC > animalCount){
		for(uint ii=animalCount;ii<newC;ii++){
	if(newC > animalListMax){
		for(uint ii=animalListMax;ii<newC;ii++){
			animalList[ii].type = 0;
		}
	}
	animalCount   = newC;
	animalListMax = newC;
	const uint i  = p->v.u16[4];
	if (i >= animalCount){ return; }
	if (i >= animalListMax){ return; }
	animal *e     = &animalList[i];

	e->pos        = vecNewP(&p->v.f[3]);


@@ 138,7 138,7 @@ void animalSyncFromServer(const packet *p){
void animalGotHitPacket(const packet *p){
	const being target  = p->v.u32[1];
	if(beingType(target) != BEING_ANIMAL){return;}
	if(beingID(target) > animalCount)    {return;}
	if(beingID(target) > animalListMax)  {return;}
	animal *c = &animalList[beingID(target)];
	fxBleeding(c->pos,target,p->v.i16[0],p->v.u16[1]);
	c->effectValue = 31;

M client/src/game/character.c => client/src/game/character.c +19 -1
@@ 431,6 431,23 @@ static float characterBlockRepulsion(character *c, float *vel){
	return blockRepulsion(c->pos,vel,80.f,characterCollisionBlock);
}

// ToDo: Check blockRepulsion and also set Positions */
static void characterBeingCollisionCallback(vec pos, being b, being source){
	if(beingType(b) != BEING_ANIMAL){return;}
	const vec beingPos = beingGetPos(b);
	const vec delta = vecSub(pos, beingPos);
	//const float power = (2.f - vecMag(delta));
	const vec deltaS = vecMulS(vecNorm(delta),0.0001f);
	const float weightDistribution = beingGetWeight(source) / beingGetWeight(b);
	beingAddVel(b,vecMulS(deltaS,weightDistribution));
	msgBeingMove(b,vecZero(),vecMulS(deltaS,-weightDistribution));
	beingAddVel(source,vecMulS(deltaS,(-1.f + weightDistribution)));
}

static void characterCheckForAnimalCollision(character *c){
	beingGetInSphere(c->pos, 2.f, characterGetBeing(c), characterBeingCollisionCallback);
}

static int characterPhysics(character *c){
	int ret=0;
	u32 col;


@@ 511,6 528,7 @@ static int characterPhysics(character *c){
		newParticle(c->pos.x,c->pos.y,c->pos.z,0.f,0.f,0.f,78.f,2.5f,cloudCT[c->cloudyness&0x1F]|0xFF000000, MAX(32,MIN(768,c->cloudyness*2)));
	}

	characterCheckForAnimalCollision(c);
	characterUpdateCons(c,oldCol,oldPos);
	updateGlide(c);
	return ret;


@@ 665,7 683,7 @@ void characterUpdate(character *c){
	characterUpdateInaccuracy(c);
	characterUpdateYOff(c);
	characterUpdateAnimation(c);
	characterHP(c,0);
	characterCheckHealth(c);
}

void charactersUpdate(){

M client/src/gui/chat.c => client/src/gui/chat.c +3 -2
@@ 27,13 27,13 @@
#include "../network/chat.h"
#include "../sdl/sdl.h"

#include <stdio.h>
#include <string.h>

widget *chatPanel;
widget *chatText;

bool chatOpen(){
	if(gameControlsInactive()){return true;}
	widgetSlideH(chatPanel, 64);
	widgetFocus(chatText);
	return false;


@@ 73,10 73,11 @@ void handlerChatSelectNext(widget *wid){
void handlerChatBlur(widget *wid){
	(void)wid;
	chatResetHistorySel();
	handlerRootHud(wid);
}

void chatInit(){
	chatText  = widgetNewCPLH(wTextInput,chatPanel,16,16,440,32,"Chat Message","submit",handlerChatSubmit);
	chatText = widgetNewCPLH(wTextInput,chatPanel,16,16,440,32,"Chat Message","submit",handlerChatSubmit);
	widgetBind(chatText,"blur",handlerChatBlur);
	widgetBind(chatText,"selectPrev",handlerChatSelectPrev);
	widgetBind(chatText,"selectNext",handlerChatSelectNext);

M client/src/gui/gui.c => client/src/gui/gui.c +1 -1
@@ 450,7 450,7 @@ void drawDebuginfo(){
		textMeshPrintf(guim,"Cloudyness  : %i\n",player->cloudyness);

		animalOverlaysDrawn = 0;
		for(uint i=0;i<animalCount;i++){
		for(uint i=0;i<animalListMax;i++){
			drawAnimalDebugOverlay(&animalList[i],i);
		}
	}

M client/src/gui/lispInput.c => client/src/gui/lispInput.c +11 -4
@@ 94,6 94,16 @@ void lispPanelToggle(){
	}
}

void handlerLispReset(widget *wid){
	(void)wid;
	lispAutoCompleteLen = 0;
	lispAutoCompleteSelection = 0;
	lispAutoCompleteCompleteSymbol = NULL;
	lispAutoCompleteStart = 0;
	lispAutoCompleteEnd = 0;
	lispInputCheckCountdown = 1;
}

void handlerLispSubmit(widget *wid){
	char buf[8192];
	if(lispInput->vals[0] == 0){return;}


@@ 182,6 192,7 @@ void lispInputInit(){
	lispLog->flags |= WIDGET_LISP;
	lispInput = widgetNewCP(wTextInput,lispPanel,0,-1,-1,32);
	lispInput->flags |= WIDGET_LISP;
	widgetBind(lispInput,"change",handlerLispReset);
	widgetBind(lispInput,"submit",handlerLispSubmit);
	widgetBind(lispInput,"selectPrev",handlerLispSelectPrev);
	widgetBind(lispInput,"selectNext",handlerLispSelectNext);


@@ 213,7 224,6 @@ void lispPanelGetPointSymbol(){
}

void lispPanelCheckAutoComplete(){
	static u64 lastSel = 0;
	if(widgetFocused == NULL){
		lispInputCheckCountdown = -1;
	}


@@ 221,10 231,7 @@ void lispPanelCheckAutoComplete(){
	if(--lispInputCheckCountdown >= 0){return;}
	lispPanelGetPointSymbol();
	if(lispAutoCompleteEnd <= lispAutoCompleteStart){return;}
	const u64 newSel = lispAutoCompleteEnd ^ lispAutoCompleteStart;
	if(newSel == lastSel){return;}
	lispAutoCompleteCompleteSymbol = false;
	lastSel = newSel;
	lispAutoCompleteSelection = -1;
	lispAutoCompleteLen = 0;
	lVal *newAC = lSearchClosureSym(lCloI(clRoot),NULL,&widgetFocused->vals[lispAutoCompleteStart],lispAutoCompleteEnd - lispAutoCompleteStart);

M client/src/gui/textInput.c => client/src/gui/textInput.c +0 -3
@@ 183,9 183,6 @@ void textInputCheckMark(const SDL_Event *e){
bool textInputEvent(const SDL_Event *e){
	if(!textInputActive()){return false;}
	if(!textInputStarted){textInputFocus(widgetFocused);}
	if((widgetFocused != NULL) && (widgetFocused->type == wTextInput) && (widgetFocused->flags & WIDGET_LISP)){
		lispInputCheckCountdown = 1;
	}

	switch(e->type){
	case SDL_TEXTINPUT:

M client/src/gui/widget.c => client/src/gui/widget.c +9 -6
@@ 457,11 457,6 @@ void widgetChildPre(widget *parent, widget *child){
void widgetFocus(widget *w){
	if(w == widgetFocused){return;}
	widgetFocused = w;
	if(widgetFocused != NULL){
		widgetEmit(widgetFocused,"blur");
	}
	if(w == NULL){return;}
	widgetEmit(w,"focus");
}

static int widgetIsSelectable(const widget *cur){


@@ 560,6 555,7 @@ void widgetBindL(widget *w, const char *eventName, lVal *handler){

int widgetEmit(widget *w, const char *eventName){
	int ret = 0;
	if(w == NULL){return 0;}
	for(eventHandler *h=w->firstHandler;h!=NULL;h=h->next){
		if(strcmp(eventName,h->eventName) != 0){continue;}
		if(h->lisp){


@@ 616,7 612,6 @@ static void widgetCheckEvents(widget *wid, int x, int y, int w, int h){
			wid->flags &= ~WIDGET_MID_CLICKED;
		}
	}else{
		if(wid->flags & WIDGET_HOVER){widgetEmit(wid,"blur");}
		wid->flags &= ~(WIDGET_HOVER | WIDGET_CLICKED);
	}
}


@@ 765,3 760,11 @@ void widgetLabel(widget *w, const char *newLabel){
	snprintf(buf,len,"%s",newLabel);
	w->label = buf;
}

void widgetUpdateAllEvents(){
	static widget *lastFocused = NULL;
	if(widgetFocused == lastFocused){return;}
	widgetEmit(lastFocused,"blur");
	lastFocused = widgetFocused;
	widgetEmit(widgetFocused,"focus");
}

M client/src/gui/widget.h => client/src/gui/widget.h +1 -0
@@ 107,3 107,4 @@ void    widgetSlideH  (widget *w, int nh);
void    widgetSlideX  (widget *w, int nw);
void    widgetSlideY  (widget *w, int nh);
void    widgetAddEntry(widget *w, const char *entry);
void    widgetUpdateAllEvents();

M client/src/main.c => client/src/main.c +7 -1
@@ 166,8 166,14 @@ void worldUpdate(){
	commitOverlayColor();
}

void mainloop(){
static void UIStuff(){
	handleEvents();
	widgetUpdateAllEvents();
	inventoryCheckCursorItem();
}

void mainloop(){
	UIStuff();
	if(gameRunning){
		clientTranceive();
		playerUpdate();

M client/src/menu/inventory.c => client/src/menu/inventory.c +9 -4
@@ 298,10 298,6 @@ void showCrafting(){
void hideInventory(){
	if(!gameRunning){return;}
	inventoryOpen = false;
	if(!itemIsEmpty(&inventoryCurrentPickup)){
		itemDropNewC(player, &inventoryCurrentPickup);
		itemDiscard(&inventoryCurrentPickup);
	}
	showInventoryPanel();
	widgetFocus(widgetGameScreen);
}


@@ 362,3 358,12 @@ void hideInventoryPanel(){
	widgetSlideW(craftingSpace,                0);
	widgetSlideW(equipmentSpace,               0);
}

void inventoryCheckCursorItem(){
	printf("Check Item!\n");
	if(isInventoryOpen()){return;}
	if(!itemIsEmpty(&inventoryCurrentPickup)){
		itemDropNewC(player, &inventoryCurrentPickup);
		itemDiscard(&inventoryCurrentPickup);
	}
}

M client/src/menu/inventory.h => client/src/menu/inventory.h +1 -0
@@ 13,3 13,4 @@ void initInventory      ();
void drawInventory      (textMesh *guim);
void showInventoryPanel ();
void hideInventoryPanel ();
void inventoryCheckCursorItem();

M client/src/menu/mainmenu.c => client/src/menu/mainmenu.c +0 -1
@@ 14,7 14,6 @@
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "mainmenu.h"

#include "../main.h"

M client/src/nujel/input_keyboard.nuj => client/src/nujel/input_keyboard.nuj +1 -0
@@ 110,6 110,7 @@
[arr-set! input-keyboard-handler key-print [λ [code value] [when value [screenshot]]]]
[arr-set! input-keyboard-handler key-tab [λ [code value] [when value [toggle-inventory!]]]]
[arr-set! input-keyboard-handler key-t [λ [code value] [when value [toggle-chat!]]]]
[arr-set! input-keyboard-handler key-y [λ [code value] [when value [toggle-chat!]]]]

[unless [eq? OS "Emscripten"]
	[arr-set! input-keyboard-handler key-f11 [λ [code value]

M common/src/animals/bunny.c => common/src/animals/bunny.c +2 -1
@@ 151,7 151,7 @@ static void bunnySFight(animal *e,int stateChange[16]){
	stateChange[ANIMAL_S_FLEE] += rngValA(127) + e->stateTicks;
}

static void bunnySFlee(animal *e,int stateChange[16]){
static void bunnySFlee(animal *e, int stateChange[16]){
	e->grot.pitch = 0.f;
	if(e->type != 2){
		if((fabsf(e->gvel.x) + fabsf(e->gvel.z)) < 0.02f){


@@ 168,6 168,7 @@ static void bunnySFlee(animal *e,int stateChange[16]){
}

static void bunnyFightOrFlight(animal *e,int stateChange[16]){
	return;
	if(e->state == ANIMAL_S_FIGHT){
		if(e->target == 0){e->target = animalFindFOFTarget(e);}
		if(e->target != 0){

M common/src/game/animal.c => common/src/game/animal.c +28 -21
@@ 39,8 39,8 @@
#define ANIMAL_MAX (1<<12)

animal  animalList[ANIMAL_MAX];
uint    animalListMax   = 0;
uint    animalCount     = 0;
uint    animalUsedCount = 0;
uint    animalFirstFree = 0xFFFFFFFF;

void animalReset(animal *e){


@@ 54,12 54,12 @@ animal *animalNew(const vec pos , int type, int gender){
		e = &animalList[animalFirstFree];
		animalFirstFree = e->nextFree;
	}else{
		if(animalCount >= countof(animalList)){
		if(animalListMax >= countof(animalList)){
			e = &animalList[rngValA(ANIMAL_MAX-1)];
			animalDel(e-animalList);
			return animalNew(pos,type,gender);
		}
		e = &animalList[animalCount++];
		e = &animalList[animalListMax++];
	}
	animalReset(e);



@@ 87,14 87,14 @@ animal *animalNew(const vec pos , int type, int gender){
	}

	if(type == animalGuardian){e->flags |= ANIMAL_NO_NEEDS;}
	animalUsedCount++;
	animalCount++;

	return e;
}

void animalDel(uint i){
	if(i >= animalCount){
		printf("AnimalDel: %u > %u\n",i,animalCount);
	if(i >= animalListMax){
		printf("AnimalDel: %u > %u\n",i,animalListMax);
		return;
	}
	beingListDel(animalList[i].bl,beingAnimal(i));


@@ 107,13 107,13 @@ void animalDel(uint i){
	animalList[i].type     = 0;
	animalList[i].nextFree = animalFirstFree;
	animalFirstFree        = i;
	animalUsedCount--;
	animalCount--;
}

void animalDelChungus(const chungus *c){
	if(c == NULL){return;}
	const vec cp = chungusGetPos(c);
	for(uint i=0;i<animalCount;i++){
	for(uint i=0;i<animalListMax;i++){
		if(animalList[i].type == 0)  {continue;}
		const vec *p = &animalList[i].pos;
		if(((int)p->x >> 8) != cp.x){continue;}


@@ 205,7 205,7 @@ void animalChaseTarget(animal *e){
int animalUpdate(animal *e){
	int ret=0;
	u32 col;
	if(e->type == 0)       {return 0;}
	if(e->type == 0){return 0;}
	e->pos = vecAdd(e->pos,e->vel);
	if(!worldShouldBeLoaded(e->pos)){return -1;}
	if(!vecInWorld(e->pos)){return 1;}


@@ 307,7 307,7 @@ const char *animalGetStateName(const animal *e){
	}
}

int animalGetMaxHealth (const animal *e){
int animalGetMaxHealth(const animal *e){
	switch((animalType)e->type){
	case animalUnused:
		return  0;


@@ 321,7 321,7 @@ int animalGetMaxHealth (const animal *e){
	return 0;
}

float animalGetWeight (const animal *e){
float animalGetWeight(const animal *e){
	switch((animalType)e->type){
	case animalUnused:
		return 2.f;


@@ 338,7 338,7 @@ float animalGetWeight (const animal *e){
animal *animalGetByBeing(being b){
	const uint i = beingID(b);
	if(beingType(b) != BEING_ANIMAL){ return NULL; }
	if(i >= animalCount)            { return NULL; }
	if(i >= animalListMax)          { return NULL; }
	return &animalList[i];
}



@@ 348,7 348,7 @@ being animalGetBeing(const animal *c){
}

animal *animalClosest(const vec pos, float maxDistance){
	for(uint i=0;i<animalCount;i++){
	for(uint i=0;i<animalListMax;i++){
		if(animalList[i].type == 0){continue;}
		const float d = vecMag(vecSub(pos,animalList[i].pos));
		if(d > maxDistance){continue;}


@@ 358,7 358,7 @@ animal *animalClosest(const vec pos, float maxDistance){
}

static void animalUpdateBL(){
	for(uint i=0;i<animalCount;i++){
	for(uint i=0;i<animalListMax;i++){
		if(animalList[i].type == 0){continue;}
		animal *a = &animalList[i];
		a->bl = beingListUpdate(a->bl,animalGetBeing(a));


@@ 368,7 368,7 @@ static void animalUpdateBL(){
void animalUpdateAll(){
	PROFILE_START();

	for(int i=animalCount-1;i>=0;i--){
	for(int i=animalListMax-1;i>=0;i--){
		if(animalList[i].type == 0){continue;}
		int dmg = animalUpdate(&animalList[i]);
		animalList[i].health -= dmg;


@@ 412,7 412,7 @@ float animalClosestPlayer(const animal *e, character **cChar){
float animalClosestAnimal(const animal *e, animal **cAnim, int typeFilter, uint flagsMask, uint flagsCompare){
	*cAnim = NULL;
	float ret = 256.f*256.f;
	for(uint i=0;i<animalCount;i++){
	for(uint i=0;i<animalListMax;i++){
		if(animalList[i].type == 0)                                {continue;}
		if(e == &animalList[i])                                    {continue;}
		if((typeFilter >= 0) && (animalList[i].type != typeFilter)){continue;}


@@ 506,7 506,7 @@ void animalThinkAll(){
	PROFILE_START();

	static uint calls = 0;
	for(uint i=(calls&0x1F);i<animalCount;i+=0x20){
	for(uint i=(calls&0x1F);i<animalListMax;i+=0x20){
		animalThink(&animalList[i]);
	}
	calls++;


@@ 522,7 522,7 @@ void animalNeedsAll(){
	int tcat = gtimeGetTimeCat();
	if((tcat == TIME_NIGHT) || (tcat == TIME_EVENING)){sleepyi = 2;}

	for(uint i=(calls&0xFFF);i<animalCount;i+=0x1000){
	for(uint i=(calls&0xFFF);i<animalListMax;i+=0x1000){
		animal *e = &animalList[i];
		if(e->flags & ANIMAL_NO_NEEDS){continue;}
		e->hunger--;


@@ 553,7 553,7 @@ void animalRBurn(animal *e){

void animalCheckBurnAll(){
	static uint calls = 0;
	for(uint i=(calls&0x7F);i<animalCount;i+=0x80){
	for(uint i=(calls&0x7F);i<animalListMax;i+=0x80){
		animal *a = &animalList[i];
		fire *f = fireGetAtPos(a->pos.x,a->pos.y,a->pos.z);
		if(f == NULL)       {continue;}


@@ 579,7 579,7 @@ void animalSync(u8 c, u16 i){
	rp->v.i8[ 7] = e->sleepy;

	rp->v.u16[4] = i;
	rp->v.u16[5] = animalCount;
	rp->v.u16[5] = animalListMax;

	rp->v.f[ 3]  = e->pos.x;
	rp->v.f[ 4]  = e->pos.y;


@@ 616,7 616,7 @@ void animalSyncInactive(u8 c, u16 i){
	rp->v.u8[ 0] = 0;

	rp->v.u16[4] = i;
	rp->v.u16[5] = animalCount;
	rp->v.u16[5] = animalListMax;

	packetQueue(rp,msgtAnimalSync,17*4,c);
}


@@ 671,3 671,10 @@ const char *animalGetName(const animal *e){
	}
	return "Unknown";
}

void animalDeleteAll(){
	for(uint i=0;i<animalListMax;i++){
		if(animalList[i].type == 0){continue;}
		animalDel(i);
	}
}

M common/src/game/animal.h => common/src/game/animal.h +3 -2
@@ 9,9 9,10 @@ typedef enum {
} animalType;

extern animal  animalList[1<<12];
extern uint    animalListMax;
extern uint    animalCount;
extern uint    animalUsedCount;

void        animalDeleteAll        ();
animal     *animalNew              (const vec pos , int type, int gender);
void        animalDel              (uint i);
void        animalDelChungus       (const chungus *c);


@@ 19,7 20,7 @@ void        animalReset            (      animal *e);
float       animalDistance         (const animal *e,const character *c);
const char *animalGetStateName     (const animal *e);
int         animalGetMaxHealth     (const animal *e);
float        animalGetWeight        (const animal *e);
float       animalGetWeight        (const animal *e);
int         animalUpdate           (      animal *e);
void        animalThink            (      animal *e);
float       animalClosestAnimal    (const animal *e, animal **cAnim, int typeFilter, uint flagsMask, uint flagsCompare);

M common/src/game/being.c => common/src/game/being.c +29 -1
@@ 299,7 299,7 @@ float beingGetWeight(being b){
	case BEING_CHARACTER:
		return 80.f;
	case BEING_ANIMAL:
		return 10.f;
		return 5.f;
	case BEING_HOOK:
		return 1.f;
	case BEING_GRENADE:


@@ 500,3 500,31 @@ const char *beingGetName(being b){
		return NULL;
	}
}

static void beingListGetInSphere(beingList *bl, vec pos, float r, being source, void (*callback)(vec pos, being b, being source)){
	if(bl == NULL){return;}
	for(beingListEntry *ble = bl->first; ble != NULL; ble = ble->next){
		for(uint i=0;i<countof(ble->v);i++){
			const being b = ble->v[i];
			if(b == 0)     {break;}
			if(b == source){continue;}
			const float distance = vecMag(vecSub(pos,beingGetPos(ble->v[i])));
			if(distance < r){
				callback(pos,b,source);
			}
		}
	}
}

void beingGetInSphere(vec pos, float r, being ignore, void (*callback)(vec pos, being b, being source)){
	const int xMax = (int)(pos.x + r) + 1 + 16;
	const int yMax = (int)(pos.y + r) + 1 + 16;
	const int zMax = (int)(pos.z + r) + 1 + 16;
	for(int x = (pos.x - r); x < xMax; x += 16){
	for(int y = (pos.y - r); y < yMax; y += 16){
	for(int z = (pos.z - r); z < zMax; z += 16){
		beingListGetInSphere(beingListGet(x,y,z),pos,r,ignore,callback);
	}
	}
	}
}

M common/src/game/being.h => common/src/game/being.h +1 -0
@@ 39,3 39,4 @@ void            beingListEntryInit();
beingListEntry *beingListEntryNew ();
void            beingListEntryFree(beingListEntry *ble);
void            beingListPrint(beingList *bl);
void            beingGetInSphere(vec pos, float r, being source, void (*callback)(vec pos, being b, being source));

M common/src/game/character.c => common/src/game/character.c +6 -2
@@ 257,8 257,7 @@ bool characterPlaceBlock(character *c,item *i){
	}
}

bool characterHP(character *c, int addhp){
	c->hp += addhp;
bool characterCheckHealth(character *c){
	if(c->hp <= 0){
		characterDie(c);
		return true;


@@ 269,6 268,11 @@ bool characterHP(character *c, int addhp){
	return false;
}

bool characterHP(character *c, int addhp){
	c->hp += addhp;
	return characterCheckHealth(c);
}

void characterEmptyInventory(character *c){
	for(uint i=0;i<CHAR_INV_MAX;i++){
		c->inventory[i] = itemEmpty();

M common/src/game/character.h => common/src/game/character.h +1 -0
@@ 40,6 40,7 @@ void       characterStartAnimation (      character *c, animType index, int dura
bool       characterTryToShoot     (      character *c, item *i, int cooldown, int bulletcount);
bool       characterTryToUse       (      character *c, item *i, int cooldown, int itemcount);
bool       characterHP             (      character *c, int addhp);
bool       characterCheckHealth    (      character *c);
bool       characterDamage         (      character *c, int hp);
int        characterGetItemAmount  (const character *c, u16 itemID);
int        characterDecItemAmount  (      character *c, u16 itemID, int amount);

M common/src/game/hook.c => common/src/game/hook.c +6 -2
@@ 116,8 116,12 @@ bool hookUpdate(hook *ghk){
		if(!(ghk->ent->flags & ENTITY_COLLIDE) && (ghk->attached == 0)){
			hookReturnHook(ghk);
		}
		if((ghk->attached != 0) && (ghk->rope->a == 0)){
			hookReturnHook(ghk);
		if(ghk->attached != 0){
			if((ghk->rope->a == 0) || (ghk->rope->b == 0)){
				hookReturnHook(ghk);
			}else{
				ghk->ent->pos = beingGetPos(ghk->attached);
			}
		}
	}else{
		if(!ghk->hooked && !ghk->returning && (ghk->ent->flags & ENTITY_COLLIDE)){

M server/src/game/animal.c => server/src/game/animal.c +4 -4
@@ 44,7 44,7 @@ static void animalServerSync(u8 c, u16 i){
}

void animalSyncPlayer(u8 c){
	if(animalCount == 0){
	if(animalListMax == 0){
		animalEmptySync(c);
		return;
	}


@@ 54,7 54,7 @@ void animalSyncPlayer(u8 c){
	for(uint tries = 256;count >= 0;clients[c].animalUpdateOffset++){
		if(--tries == 0){break;}
		const uint i = clients[c].animalUpdateOffset;
		if(i >= animalCount){clients[c].animalUpdateOffset = 0;}
		if(i >= animalListMax){clients[c].animalUpdateOffset = 0;}
		if(animalList[i].clientPriorization & mask){continue;}
		animalServerSync(c,i);
		count--;


@@ 64,7 64,7 @@ void animalSyncPlayer(u8 c){
	for(uint tries=2048;count >= 0;clients[c].animalPriorityUpdateOffset++){
		if(--tries == 0){break;}
		const uint i = clients[c].animalPriorityUpdateOffset;
		if(i >= animalCount){clients[c].animalPriorityUpdateOffset = 0;}
		if(i >= animalListMax){clients[c].animalPriorityUpdateOffset = 0;}
		if(!(animalList[i].clientPriorization & mask)){continue;}
		animalServerSync(c,i);
		count--;


@@ 85,7 85,7 @@ void animalUpdatePriorities(u8 c){
	if(clients[c].state)     {return;}
	if(clients[c].c == NULL) {return;}
	const vec cpos = clients[c].c->pos;
	for(uint i=0;i<animalCount;i++){
	for(uint i=0;i<animalListMax;i++){
		const float d = vecMag(vecSub(animalList[i].pos,cpos));
		if(d < 78.f){
			animalList[i].clientPriorization |= prio;

M server/src/misc/lisp.c => server/src/misc/lisp.c +9 -2
@@ 247,7 247,7 @@ static lVal *wwlnfSetAnim(lClosure *c, lVal *v){
	v = getLArgI(c,v,&state);
	v = getLArgI(c,v,&health);

	if((index < 0) || (index > (int)animalCount)){return NULL;}
	if((index < 0) || (index > (int)animalListMax)){return NULL;}
	animal *a = &animalList[index];
	if(a->type ==  0){return NULL;}
	if(hunger >=  0){a->hunger    = hunger;}


@@ 293,7 293,7 @@ static lVal *wwlnfLShed(lClosure *c, lVal *v){
	(void)c;(void)v;

	chungusFreeOldChungi(100);
	for(uint i = animalCount/2-1;i < animalCount;i--){
	for(uint i = animalListMax/2-1;i < animalListMax;i--){
		if(animalList[i].type == 0){continue;}
		animalDel(i);
	}


@@ 492,9 492,16 @@ static lVal *wwlnfItemDropNew(lClosure *c, lVal *v){
	return NULL;
}

lVal *wwlnfAnimalKillAll(lClosure *c, lVal *v){
	(void)c; (void) v;
	animalDeleteAll();
	return NULL;
}

void addServerNativeFuncs(lClosure *c){
	lAddNativeFunc(c,"player-pos",     "()",                                           "Returns player pos vector",                                  wwlnfPlayerPos);
	lAddNativeFunc(c,"animal-count",   "()",                                           "Returns animal count",                                       wwlnfACount);
	lAddNativeFunc(c,"animal-kill-all","()",                                           "Returns animal count",                                       wwlnfAnimalKillAll);
	lAddNativeFunc(c,"fire-count",     "()",                                           "Returns fire count",                                         wwlnfFCount);
	lAddNativeFunc(c,"mining-count",   "()",                                           "Returns block mining count",                                 wwlnfBMCount);
	lAddNativeFunc(c,"item-drop-count","()",                                           "Returns item drop count",                                    wwlnfIDCount);

M server/src/persistence/animal.c => server/src/persistence/animal.c +1 -1
@@ 91,7 91,7 @@ const void *animalLoad(const void *buf){
void *animalSaveChungus(const chungus *c,void *b){
	if(c == NULL){return b;}
	const u32 cc = c->x | (c->y << 8) | (c->z << 16);
	for(uint i=0;i<animalCount;i++){
	for(uint i=0;i<animalListMax;i++){
		const vec *p = &animalList[i].pos;
		const u32 ac = ((uint)p->x >> 8) | ((uint)p->y & 0xFF00) | (((uint)p->z << 8) & 0xFF0000);
		if(ac != cc){continue;}