the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "LocalPlayer.h"
3#include "User.h"
4#include "Input.h"
5#include "StatsCounter.h"
6#include "ParticleEngine.h"
7#include "TakeAnimationParticle.h"
8#include "Options.h"
9#include "TextEditScreen.h"
10#include "ContainerScreen.h"
11#include "CraftingScreen.h"
12#include "FurnaceScreen.h"
13#include "TrapScreen.h"
14
15#include "MultiPlayerLocalPlayer.h"
16#include "CreativeMode.h"
17#include "GameRenderer.h"
18#include "ItemInHandRenderer.h"
19#include "..\Minecraft.World\AttributeInstance.h"
20#include "..\Minecraft.World\LevelData.h"
21#include "..\Minecraft.World\net.minecraft.world.damagesource.h"
22#include "..\Minecraft.World\net.minecraft.world.item.h"
23#include "..\Minecraft.World\net.minecraft.world.food.h"
24#include "..\Minecraft.World\net.minecraft.world.effect.h"
25#include "..\Minecraft.World\net.minecraft.world.entity.player.h"
26#include "..\Minecraft.World\net.minecraft.world.entity.monster.h"
27#include "..\Minecraft.World\ItemEntity.h"
28#include "..\Minecraft.World\net.minecraft.world.level.h"
29#include "..\Minecraft.World\net.minecraft.world.level.tile.entity.h"
30#include "..\Minecraft.World\net.minecraft.world.phys.h"
31#include "..\Minecraft.World\net.minecraft.stats.h"
32#include "..\Minecraft.World\com.mojang.nbt.h"
33#include "..\Minecraft.World\Random.h"
34#include "..\Minecraft.World\TileEntity.h"
35#include "..\Minecraft.World\Mth.h"
36#include "AchievementPopup.h"
37#include "CritParticle.h"
38
39// 4J : WESTY : Added for new achievements.
40#include "..\Minecraft.World\item.h"
41#include "..\Minecraft.World\mapitem.h"
42#include "..\Minecraft.World\tile.h"
43
44// 4J Stu - Added for tutorial callbacks
45#include "Minecraft.h"
46
47#include "..\Minecraft.World\Minecart.h"
48#include "..\Minecraft.World\Boat.h"
49#include "..\Minecraft.World\Pig.h"
50
51#include "..\Minecraft.World\StringHelpers.h"
52
53#include "Options.h"
54#include "..\Minecraft.World\Dimension.h"
55
56#ifndef _DURANGO
57#include "..\Minecraft.World\CommonStats.h"
58#endif
59
60
61
62LocalPlayer::LocalPlayer(Minecraft *minecraft, Level *level, User *user, int dimension) : Player(level, user->name)
63{
64 flyX = flyY = flyZ = 0.0f; // 4J added
65 m_awardedThisSession = 0;
66
67 sprintTriggerTime = 0;
68 sprintTriggerRegisteredReturn = false;
69 twoJumpsRegistered = false;
70 sprintTime = 0;
71 m_uiInactiveTicks=0;
72 portalTime = 0.0f;
73 oPortalTime = 0.0f;
74 jumpRidingTicks = 0;
75 jumpRidingScale = 0.0f;
76
77 yBob = xBob = yBobO = xBobO = 0.0f;
78
79 this->minecraft = minecraft;
80 this->dimension = dimension;
81
82 if (user != NULL && user->name.length() > 0)
83 {
84 customTextureUrl = L"http://s3.amazonaws.com/MinecraftSkins/" + user->name + L".png";
85 }
86 if( user != NULL )
87 {
88 this->name = user->name;
89 //wprintf(L"Created LocalPlayer with name %ls\n", name.c_str() );
90 // check to see if this player's xuid is in the list of special players
91 MOJANG_DATA *pMojangData=app.GetMojangDataForXuid(getOnlineXuid());
92 if(pMojangData)
93 {
94 customTextureUrl=pMojangData->wchSkin;
95 }
96
97 }
98 input = NULL;
99 m_iPad = -1;
100 m_iScreenSection=C4JRender::VIEWPORT_TYPE_FULLSCREEN; // assume singleplayer default
101 m_bPlayerRespawned=false;
102 ullButtonsPressed=0LL;
103 ullDpad_last = ullDpad_this = ullDpad_filtered = 0;
104
105 // 4J-PB - moved in from the minecraft structure
106 //ticks=0;
107 missTime=0;
108 lastClickTick[0] = 0;
109 lastClickTick[1] = 0;
110 isRaining=false;
111
112 m_bIsIdle = false;
113 m_iThirdPersonView=0;
114
115 // 4J Stu - Added for telemetry
116 SetSessionTimerStart();
117
118 // 4J - added for auto repeat in creative mode
119 lastClickState = lastClick_invalid;
120 lastClickTolerance = 0.0f;
121
122 m_bHasAwardedStayinFrosty = false;
123}
124
125LocalPlayer::~LocalPlayer()
126{
127 if( this->input != NULL )
128 delete input;
129}
130
131void LocalPlayer::calculateFlight(float xa, float ya, float za)
132{
133 xa = xa * minecraft->options->flySpeed;
134 ya = 0;
135 za = za * minecraft->options->flySpeed;
136
137 flyX = smoothFlyX.getNewDeltaValue(xa, .35f * minecraft->options->sensitivity);
138 flyY = smoothFlyY.getNewDeltaValue(ya, .35f * minecraft->options->sensitivity);
139 flyZ = smoothFlyZ.getNewDeltaValue(za, .35f * minecraft->options->sensitivity);
140}
141
142void LocalPlayer::serverAiStep()
143{
144 Player::serverAiStep();
145
146 if( abilities.flying && abilities.mayfly )
147 {
148 // snap y rotation for flying to nearest 90 degrees in world space
149 float fMag = sqrtf(input->xa * input->xa + input->ya * input->ya);
150 // Don't bother for tiny inputs
151 if( fMag >= 0.1f )
152 {
153 // Get angle (in player rotated space) of input controls
154 float yRotInput = atan2f(input->ya, input->xa) * (180.0f / PI);
155 // Now get in world space
156 float yRotFinal = yRotInput + yRot;
157 // Snap this to nearest 90 degrees
158 float yRotSnapped = floorf((yRotFinal / 45.0f) + 0.5f) * 45.0f;
159 // Find out how much we had to move to do this snap
160 float yRotDiff = yRotSnapped - yRotFinal;
161 // Apply the same difference to the player rotated space angle
162 float yRotInputAdjust = yRotInput + yRotDiff;
163
164 // Calculate final x/y player-space movement required
165 this->xxa = cos(yRotInputAdjust * ( PI / 180.0f) ) * fMag;
166 this->yya = sin(yRotInputAdjust * ( PI / 180.0f) ) * fMag;
167 }
168 else
169 {
170 this->xxa = input->xa;
171 this->yya = input->ya;
172 }
173 }
174 else
175 {
176 this->xxa = input->xa;
177 this->yya = input->ya;
178 }
179 this->jumping = input->jumping;
180
181 yBobO = yBob;
182 xBobO = xBob;
183 xBob += (xRot - xBob) * 0.5;
184 yBob += (yRot - yBob) * 0.5;
185
186 // TODO 4J - Remove
187 //if (input->jumping)
188 // mapPlayerChunk(8);
189}
190
191bool LocalPlayer::isEffectiveAi()
192{
193 return true;
194}
195
196void LocalPlayer::aiStep()
197{
198 if (sprintTime > 0)
199 {
200 sprintTime--;
201 if (sprintTime == 0)
202 {
203 setSprinting(false);
204 }
205 }
206 if (sprintTriggerTime > 0) sprintTriggerTime--;
207 if (minecraft->gameMode->isCutScene())
208 {
209 x = z = 0.5;
210 x = 0;
211 z = 0;
212 yRot = tickCount / 12.0f;
213 xRot = 10;
214 y = 68.5;
215 return;
216 }
217 oPortalTime = portalTime;
218 if (isInsidePortal)
219 {
220 if (!level->isClientSide)
221 {
222 if (riding != NULL) this->ride(nullptr);
223 }
224 if (minecraft->screen != NULL) minecraft->setScreen(NULL);
225
226 if (portalTime == 0)
227 {
228 minecraft->soundEngine->playUI(eSoundType_PORTAL_TRIGGER, 1, random->nextFloat() * 0.4f + 0.8f);
229 }
230 portalTime += 1 / 80.0f;
231 if (portalTime >= 1)
232 {
233 portalTime = 1;
234 }
235 isInsidePortal = false;
236 }
237 else if (hasEffect(MobEffect::confusion) && getEffect(MobEffect::confusion)->getDuration() > (SharedConstants::TICKS_PER_SECOND * 3))
238 {
239 portalTime += 1 / 150.0f;
240 if (portalTime > 1)
241 {
242 portalTime = 1;
243 }
244 }
245 else
246 {
247 if (portalTime > 0) portalTime -= 1 / 20.0f;
248 if (portalTime < 0) portalTime = 0;
249 }
250
251 if (changingDimensionDelay > 0) changingDimensionDelay--;
252 bool wasJumping = input->jumping;
253 float runTreshold = 0.8f;
254 float sprintForward = input->sprintForward;
255
256 bool wasRunning = sprintForward >= runTreshold;
257 //input->tick( dynamic_pointer_cast<Player>( shared_from_this() ) );
258 // 4J-PB - make it a localplayer
259 input->tick( this );
260 sprintForward = input->sprintForward;
261 if (isUsingItem() && !isRiding())
262 {
263 input->xa *= 0.2f;
264 input->ya *= 0.2f;
265 sprintTriggerTime = 0;
266 }
267 // this.heightOffset = input.sneaking?1.30f:1.62f; // 4J - this was already commented out
268 if (input->sneaking) // 4J - removed - TODO replace
269 {
270 if (ySlideOffset < 0.2f) ySlideOffset = 0.2f;
271 }
272
273 checkInTile(x - bbWidth * 0.35, bb->y0 + 0.5, z + bbWidth * 0.35);
274 checkInTile(x - bbWidth * 0.35, bb->y0 + 0.5, z - bbWidth * 0.35);
275 checkInTile(x + bbWidth * 0.35, bb->y0 + 0.5, z - bbWidth * 0.35);
276 checkInTile(x + bbWidth * 0.35, bb->y0 + 0.5, z + bbWidth * 0.35);
277
278 bool enoughFoodToSprint = getFoodData()->getFoodLevel() > FoodConstants::MAX_FOOD * FoodConstants::FOOD_SATURATION_LOW;
279
280 // 4J Stu - If we can fly, then we should be able to sprint without requiring food. This is particularly a problem for people who save a survival
281 // world with low food, then reload it in creative.
282 if(abilities.mayfly || isAllowedToFly() ) enoughFoodToSprint = true;
283
284 bool forwardEnoughToTriggerSprint = sprintForward >= runTreshold;
285 bool forwardReturnedToDeadzone = sprintForward == 0.0f;
286 bool forwardEnoughToContinueSprint = sprintForward >= runTreshold;
287
288#ifdef _WINDOWS64
289 if (GetXboxPad() == 0 && input->usingKeyboardMovement)
290 {
291 forwardEnoughToContinueSprint = sprintForward > 0.0f;
292 }
293#endif
294
295#ifdef _WINDOWS64
296 // Keyboard sprint: Ctrl held while moving forward
297 if (GetXboxPad() == 0 && input->usingKeyboardMovement && KMInput.IsKeyDown(VK_CONTROL) && sprintForward > 0.0f &&
298 enoughFoodToSprint && !isUsingItem() && !hasEffect(MobEffect::blindness) && onGround)
299 {
300 if (!isSprinting()) setSprinting(true);
301 }
302#endif
303
304 // 4J - altered this slightly to make sure that the joypad returns to below returnTreshold in between registering two movements up to runThreshold
305 if (onGround && !isSprinting() && enoughFoodToSprint && !isUsingItem() && !hasEffect(MobEffect::blindness))
306 {
307 if( !wasRunning && forwardEnoughToTriggerSprint )
308 {
309 if (sprintTriggerTime == 0)
310 {
311 sprintTriggerTime = 7;
312 sprintTriggerRegisteredReturn = false;
313 }
314 else
315 {
316 if( sprintTriggerRegisteredReturn )
317 {
318 setSprinting(true);
319 sprintTriggerTime = 0;
320 sprintTriggerRegisteredReturn = false;
321 }
322 }
323 }
324 else if( ( sprintTriggerTime > 0 ) && forwardReturnedToDeadzone ) // zero sprintForward here signifies that we have returned to the deadzone
325 {
326 sprintTriggerRegisteredReturn = true;
327 }
328 }
329 if (isSneaking()) sprintTriggerTime = 0;
330 // 4J-PB - try not stopping sprint on collision
331 //if (isSprinting() && (input->ya < runTreshold || horizontalCollision || !enoughFoodToSprint))
332 if (isSprinting() && (!forwardEnoughToContinueSprint || !enoughFoodToSprint || isSneaking() || isUsingItem()))
333 {
334 setSprinting(false);
335 }
336
337 // 4J Stu - Fix for #52705 - Customer Encountered: Player can fly in bed while being in Creative mode.
338 if (!isSleeping() && (abilities.mayfly || isAllowedToFly() ))
339 {
340 // 4J altered to require jump button to released after being tapped twice to trigger move between flying / not flying
341 if (!wasJumping && input->jumping)
342 {
343 if (jumpTriggerTime == 0)
344 {
345 jumpTriggerTime = 7; // the 4J team changed it to 10 because of additional requirements to initiate flight
346 twoJumpsRegistered = false;
347 }
348 else
349 {
350 twoJumpsRegistered = true;
351 }
352 }
353 else if(jumpTriggerTime > 0 && twoJumpsRegistered) //the 4J team checked if the player was NOT jumping after the two jumps, aka had let go of the jump button
354 {
355#ifndef _CONTENT_PACKAGE
356 printf("flying was %s\n", abilities.flying ? "on" : "off");
357#endif
358 abilities.flying = !abilities.flying;
359#ifndef _CONTENT_PACKAGE
360 printf("flying is %s\n", abilities.flying ? "on" : "off");
361#endif
362 jumpTriggerTime = 0;
363 twoJumpsRegistered = false;
364 if( abilities.flying ) input->sneaking = false; // 4J added - would we ever intentially want to go into flying mode whilst sneaking?
365 }
366 }
367 else if(abilities.flying)
368 {
369#ifdef _DEBUG_MENUS_ENABLED
370 if(!abilities.debugflying)
371#endif
372 {
373 abilities.flying = false;
374 }
375 }
376
377
378 if (abilities.flying)
379 {
380 // yd = 0;
381 // 4J - note that the 0.42 added for going down is to make it match with what happens when you jump - jumping itself adds 0.42 to yd in Mob::jumpFromGround
382 if (ullButtonsPressed & (1LL<<MINECRAFT_ACTION_SNEAK_TOGGLE) ) yd -= ( 0.15 + 0.42 ); // 4J - for flying mode, MINECRAFT_ACTION_SNEAK_TOGGLE isn't a toggle but just indicates that this button is down
383 if (input->jumping)
384 {
385 noJumpDelay = 0;
386 yd += 0.15;
387 }
388
389 // snap y rotation to nearest 90 degree axis aligned value
390 float yRotSnapped = floorf((yRot / 90.0f) + 0.5f) * 90.0f;
391
392 if(InputManager.GetJoypadMapVal(m_iPad) == 0)
393 {
394 if( ullDpad_filtered & (1LL<<MINECRAFT_ACTION_DPAD_RIGHT))
395 {
396 xd = -0.15 * cos(yRotSnapped * PI / 180);
397 zd = -0.15 * sin(yRotSnapped * PI / 180);
398 }
399 else if( ullDpad_filtered & (1LL<<MINECRAFT_ACTION_DPAD_LEFT))
400 {
401 xd = 0.15 * cos(yRotSnapped * PI / 180);
402 zd = 0.15 * sin(yRotSnapped * PI / 180);
403 }
404 }
405 }
406
407 if (isRidingJumpable())
408 {
409 if (jumpRidingTicks < 0)
410 {
411 jumpRidingTicks++;
412 if (jumpRidingTicks == 0)
413 {
414 // reset scale (for gui)
415 jumpRidingScale = 0;
416 }
417 }
418 if (wasJumping && !input->jumping)
419 {
420 // jump release
421 jumpRidingTicks = -10;
422 sendRidingJump();
423 }
424 else if (!wasJumping && input->jumping)
425 {
426 // jump press
427 jumpRidingTicks = 0;
428 jumpRidingScale = 0;
429 }
430 else if (wasJumping)
431 {
432 // calc jump scale
433 jumpRidingTicks++;
434 if (jumpRidingTicks < 10)
435 {
436 jumpRidingScale = (float) jumpRidingTicks * .1f;
437 }
438 else
439 {
440 jumpRidingScale = .8f + (2.f / ((float) (jumpRidingTicks - 9))) * .1f;
441 }
442 }
443 }
444 else
445 {
446 jumpRidingScale = 0;
447 }
448
449 Player::aiStep();
450
451 // 4J-PB - If we're in Creative Mode, allow flying on ground
452 if(!abilities.mayfly && !isAllowedToFly() )
453 {
454 if (onGround && abilities.flying)
455 {
456#ifdef _DEBUG_MENUS_ENABLED
457 if(!abilities.debugflying)
458#endif
459 {
460 abilities.flying = false;
461 }
462 }
463 }
464
465 if( abilities.flying )//minecraft->options->isFlying )
466 {
467 Vec3* viewVector = getViewVector(1.0f);
468
469 // 4J-PB - To let the player build easily while flying, we need to change this
470
471#ifdef _DEBUG_MENUS_ENABLED
472 if(abilities.debugflying)
473 {
474 flyX = (float)viewVector->x * input->ya;
475 flyY = (float)viewVector->y * input->ya;
476 flyZ = (float)viewVector->z * input->ya;
477 }
478 else
479#endif
480 {
481 if( isSprinting() )
482 {
483 // Accelrate up to full speed if we are sprinting, moving in the direction of the view vector
484 flyX = (float)viewVector->x * input->ya;
485 flyY = (float)viewVector->y * input->ya;
486 flyZ = (float)viewVector->z * input->ya;
487
488 float scale = ((float)(SPRINT_DURATION - sprintTime))/10.0f;
489 scale = scale * scale;
490 if ( scale > 1.0f ) scale = 1.0f;
491 flyX *= scale;
492 flyY *= scale;
493 flyZ *= scale;
494 }
495 else
496 {
497 flyX = 0.0f;
498 flyY = 0.0f;
499 flyZ = 0.0f;
500 if( ullDpad_filtered & (1LL<<MINECRAFT_ACTION_DPAD_UP))
501 {
502 flyY = 0.1f;
503 }
504 if( ullDpad_filtered & (1LL<<MINECRAFT_ACTION_DPAD_DOWN))
505 {
506 flyY = -0.1f;
507 }
508 }
509 }
510
511 Player::move(flyX, flyY, flyZ);
512
513 fallDistance = 0.0f;
514 yd = 0.0f;
515 onGround = true;
516 }
517
518 // Check if the player is idle and the rich presence needs updated
519 if( !m_bIsIdle && InputManager.GetIdleSeconds( m_iPad ) > PLAYER_IDLE_TIME )
520 {
521 ProfileManager.SetCurrentGameActivity(m_iPad,CONTEXT_PRESENCE_IDLE,false);
522 m_bIsIdle = true;
523 }
524 else if ( m_bIsIdle && InputManager.GetIdleSeconds( m_iPad ) < PLAYER_IDLE_TIME )
525 {
526 // Are we offline or online, and how many players are there
527 if(g_NetworkManager.GetPlayerCount()>1)
528 {
529 // only do it for this player here - each player will run this code
530 if(g_NetworkManager.IsLocalGame())
531 {
532 ProfileManager.SetCurrentGameActivity(m_iPad,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false);
533 }
534 else
535 {
536 ProfileManager.SetCurrentGameActivity(m_iPad,CONTEXT_PRESENCE_MULTIPLAYER,false);
537 }
538 }
539 else
540 {
541 if(g_NetworkManager.IsLocalGame())
542 {
543 ProfileManager.SetCurrentGameActivity(m_iPad,CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE,false);
544 }
545 else
546 {
547 ProfileManager.SetCurrentGameActivity(m_iPad,CONTEXT_PRESENCE_MULTIPLAYER_1P,false);
548 }
549 }
550 updateRichPresence();
551 m_bIsIdle = false;
552 }
553}
554
555void LocalPlayer::changeDimension(int i)
556{
557 if (!level->isClientSide)
558 {
559 if (dimension == 1 && i == 1)
560 {
561 awardStat(GenericStats::winGame(), GenericStats::param_noArgs());
562 //minecraft.setScreen(new WinScreen());
563#ifndef _CONTENT_PACKAGE
564 app.DebugPrintf("LocalPlayer::changeDimension from 1 to 1 but WinScreen has not been implemented.\n");
565 __debugbreak();
566#endif
567 }
568 else
569 {
570 awardStat(GenericStats::theEnd(), GenericStats::param_theEnd());
571
572 minecraft->soundEngine->playUI(eSoundType_PORTAL_TRAVEL, 1, random->nextFloat() * 0.4f + 0.8f);
573 }
574 }
575}
576
577float LocalPlayer::getFieldOfViewModifier()
578{
579 float targetFov = 1.0f;
580
581 // modify for movement
582 if (abilities.flying) targetFov *= 1.1f;
583
584 AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED);
585 targetFov *= (speed->getValue() / abilities.getWalkingSpeed() + 1) / 2;
586
587 // modify for bow =)
588 if (isUsingItem() && getUseItem()->id == Item::bow->id)
589 {
590 int ticksHeld = getTicksUsingItem();
591 float scale = (float) ticksHeld / BowItem::MAX_DRAW_DURATION;
592 if (scale > 1)
593 {
594 scale = 1;
595 }
596 else
597 {
598 scale *= scale;
599 }
600 targetFov *= 1.0f - scale * .15f;
601 }
602
603 return targetFov;
604}
605
606void LocalPlayer::addAdditonalSaveData(CompoundTag *entityTag)
607{
608 Player::addAdditonalSaveData(entityTag);
609 //entityTag->putInt(L"Score", score);
610}
611
612void LocalPlayer::readAdditionalSaveData(CompoundTag *entityTag)
613{
614 Player::readAdditionalSaveData(entityTag);
615 //score = entityTag->getInt(L"Score");
616}
617
618void LocalPlayer::closeContainer()
619{
620 Player::closeContainer();
621 minecraft->setScreen(NULL);
622
623 // 4J - Close any xui here
624 // Fix for #9164 - CRASH: MP: Title crashes upon opening a chest and having another user destroy it.
625 ui.PlayUISFX(eSFX_Back);
626 ui.CloseUIScenes( m_iPad );
627}
628
629void LocalPlayer::openTextEdit(shared_ptr<TileEntity> tileEntity)
630{
631 bool success;
632
633 if (tileEntity->GetType() == eTYPE_SIGNTILEENTITY)
634 {
635 success = app.LoadSignEntryMenu(GetXboxPad(), dynamic_pointer_cast<SignTileEntity>(tileEntity));
636 }
637 else if (tileEntity->GetType() == eTYPE_COMMANDBLOCKTILEENTITY)
638 {
639 success = app.LoadCommandBlockMenu(GetXboxPad(), dynamic_pointer_cast<CommandBlockEntity>(tileEntity));
640 }
641
642 if( success ) ui.PlayUISFX(eSFX_Press);
643 //minecraft->setScreen(new TextEditScreen(sign));
644}
645
646bool LocalPlayer::openContainer(shared_ptr<Container> container)
647{
648 bool success = app.LoadContainerMenu(GetXboxPad(), inventory, container );
649 if( success ) ui.PlayUISFX(eSFX_Press);
650 //minecraft->setScreen(new ContainerScreen(inventory, container));
651 return success;
652}
653
654bool LocalPlayer::openHopper(shared_ptr<HopperTileEntity> container)
655{
656 //minecraft->setScreen(new HopperScreen(inventory, container));
657 bool success = app.LoadHopperMenu(GetXboxPad(), inventory, container );
658 if( success ) ui.PlayUISFX(eSFX_Press);
659 return success;
660}
661
662bool LocalPlayer::openHopper(shared_ptr<MinecartHopper> container)
663{
664 //minecraft->setScreen(new HopperScreen(inventory, container));
665 bool success = app.LoadHopperMenu(GetXboxPad(), inventory, container );
666 if( success ) ui.PlayUISFX(eSFX_Press);
667 return success;
668}
669
670bool LocalPlayer::openHorseInventory(shared_ptr<EntityHorse> horse, shared_ptr<Container> container)
671{
672 //minecraft->setScreen(new HorseInventoryScreen(inventory, container, horse));
673 bool success = app.LoadHorseMenu(GetXboxPad(), inventory, container, horse);
674 if( success ) ui.PlayUISFX(eSFX_Press);
675 return success;
676}
677
678bool LocalPlayer::startCrafting(int x, int y, int z)
679{
680 bool success = app.LoadCrafting3x3Menu(GetXboxPad(), dynamic_pointer_cast<LocalPlayer>( shared_from_this() ), x, y, z );
681 if( success ) ui.PlayUISFX(eSFX_Press);
682 //app.LoadXuiCraftMenu(0,inventory, level, x, y, z);
683 //minecraft->setScreen(new CraftingScreen(inventory, level, x, y, z));
684 return success;
685}
686
687bool LocalPlayer::openFireworks(int x, int y, int z)
688{
689 bool success = app.LoadFireworksMenu(GetXboxPad(), dynamic_pointer_cast<LocalPlayer>( shared_from_this() ), x, y, z );
690 if( success ) ui.PlayUISFX(eSFX_Press);
691 return success;
692}
693
694bool LocalPlayer::startEnchanting(int x, int y, int z, const wstring &name)
695{
696 bool success = app.LoadEnchantingMenu(GetXboxPad(), inventory, x, y, z, level, name);
697 if( success ) ui.PlayUISFX(eSFX_Press);
698 //minecraft.setScreen(new EnchantmentScreen(inventory, level, x, y, z));
699 return success;
700}
701
702bool LocalPlayer::startRepairing(int x, int y, int z)
703{
704 bool success = app.LoadRepairingMenu(GetXboxPad(), inventory, level, x, y, z );
705 if( success ) ui.PlayUISFX(eSFX_Press);
706 //minecraft.setScreen(new RepairScreen(inventory, level, x, y, z));
707 return success;
708}
709
710bool LocalPlayer::openFurnace(shared_ptr<FurnaceTileEntity> furnace)
711{
712 bool success = app.LoadFurnaceMenu(GetXboxPad(),inventory, furnace);
713 if( success ) ui.PlayUISFX(eSFX_Press);
714 //minecraft->setScreen(new FurnaceScreen(inventory, furnace));
715 return success;
716}
717
718bool LocalPlayer::openBrewingStand(shared_ptr<BrewingStandTileEntity> brewingStand)
719{
720 bool success = app.LoadBrewingStandMenu(GetXboxPad(),inventory, brewingStand);
721 if( success ) ui.PlayUISFX(eSFX_Press);
722 //minecraft.setScreen(new BrewingStandScreen(inventory, brewingStand));
723 return success;
724}
725
726bool LocalPlayer::openBeacon(shared_ptr<BeaconTileEntity> beacon)
727{
728 //minecraft->setScreen(new BeaconScreen(inventory, beacon));
729 bool success = app.LoadBeaconMenu(GetXboxPad(), inventory, beacon);
730 if( success ) ui.PlayUISFX(eSFX_Press);
731 return success;
732}
733
734bool LocalPlayer::openTrap(shared_ptr<DispenserTileEntity> trap)
735{
736 bool success = app.LoadTrapMenu(GetXboxPad(),inventory, trap);
737 if( success ) ui.PlayUISFX(eSFX_Press);
738 //minecraft->setScreen(new TrapScreen(inventory, trap));
739 return success;
740}
741
742bool LocalPlayer::openTrading(shared_ptr<Merchant> traderTarget, const wstring &name)
743{
744 bool success = app.LoadTradingMenu(GetXboxPad(),inventory, traderTarget, level, name);
745 if( success ) ui.PlayUISFX(eSFX_Press);
746 //minecraft.setScreen(new MerchantScreen(inventory, traderTarget, level));
747 return success;
748}
749
750void LocalPlayer::crit(shared_ptr<Entity> e)
751{
752 shared_ptr<CritParticle> critParticle = shared_ptr<CritParticle>( new CritParticle((Level *)minecraft->level, e) );
753 critParticle->CritParticlePostConstructor();
754 minecraft->particleEngine->add(critParticle);
755}
756
757void LocalPlayer::magicCrit(shared_ptr<Entity> e)
758{
759 shared_ptr<CritParticle> critParticle = shared_ptr<CritParticle>( new CritParticle((Level *)minecraft->level, e, eParticleType_magicCrit) );
760 critParticle->CritParticlePostConstructor();
761 minecraft->particleEngine->add(critParticle);
762}
763
764void LocalPlayer::take(shared_ptr<Entity> e, int orgCount)
765{
766 minecraft->particleEngine->add( shared_ptr<TakeAnimationParticle>( new TakeAnimationParticle((Level *)minecraft->level, e, shared_from_this(), -0.5f) ) );
767}
768
769void LocalPlayer::chat(const wstring& message)
770{
771}
772
773bool LocalPlayer::isSneaking()
774{
775 return input->sneaking && !m_isSleeping;
776}
777
778void LocalPlayer::hurtTo(float newHealth, ETelemetryChallenges damageSource)
779{
780 float dmg = getHealth() - newHealth;
781 if (dmg <= 0)
782 {
783 setHealth(newHealth);
784 if (dmg < 0)
785 {
786 invulnerableTime = invulnerableDuration / 2;
787 }
788 }
789 else
790 {
791 lastHurt = dmg;
792 setHealth(getHealth());
793 invulnerableTime = invulnerableDuration;
794 actuallyHurt(DamageSource::genericSource,dmg);
795 hurtTime = hurtDuration = 10;
796 }
797
798
799 if( this->getHealth() <= 0)
800 {
801 int deathTime = (int)(level->getGameTime() % Level::TICKS_PER_DAY)/1000;
802 int carriedId = inventory->getSelected() == NULL ? 0 : inventory->getSelected()->id;
803 TelemetryManager->RecordPlayerDiedOrFailed(GetXboxPad(), 0, y, 0, 0, carriedId, 0, damageSource);
804
805 // if there are any xuiscenes up for this player, close them
806 if(ui.GetMenuDisplayed(GetXboxPad()))
807 {
808 ui.CloseUIScenes(GetXboxPad());
809 }
810 }
811
812}
813
814void LocalPlayer::respawn()
815{
816 // Select the right payer to respawn
817 minecraft->respawnPlayer(GetXboxPad(), 0, 0);
818}
819
820void LocalPlayer::animateRespawn()
821{
822// Player.animateRespawn(this, level);
823}
824
825void LocalPlayer::displayClientMessage(int messageId)
826{
827 minecraft->gui->displayClientMessage(messageId, GetXboxPad());
828}
829
830void LocalPlayer::awardStat(Stat *stat, byteArray param)
831{
832#ifdef _DURANGO
833 // 4J-JEV: Maybe we want to fine tune this later? #TODO
834 if ( !ProfileManager.IsGuest(GetXboxPad())
835 && app.CanRecordStatsAndAchievements()
836 && ProfileManager.IsFullVersion()
837 )
838 {
839 stat->handleParamBlob(dynamic_pointer_cast<LocalPlayer>(shared_from_this()), param);
840 }
841 delete [] param.data;
842#else
843 int count = CommonStats::readParam(param);
844 delete [] param.data;
845
846 if (!app.CanRecordStatsAndAchievements()) return;
847 if (stat == NULL) return;
848
849 if (stat->isAchievement())
850 {
851 Achievement *ach = (Achievement *) stat;
852 // 4J-PB - changed to attempt to award everytime - the award may need a storage device, so needs a primary player, and the player may not have been a primary player when they first 'got' the award
853 // so let the award manager figure it out
854 //if (!minecraft->stats[m_iPad]->hasTaken(ach))
855 {
856 // 4J-PB - Don't display the java popup
857 //minecraft->achievementPopup->popup(ach);
858
859 // 4J Stu - Added this function in the libraries as some achievements don't get awarded to all players
860 // e.g. Splitscreen players cannot get theme/avatar/gamerpic and Trial players cannot get any
861 // This causes some extreme flooding of some awards
862 if(ProfileManager.CanBeAwarded(m_iPad, ach->getAchievementID() ) )
863 {
864 // 4J Stu - We don't (currently) care about the gamerscore, so setting to a default of 0 points
865 TelemetryManager->RecordAchievementUnlocked(m_iPad,ach->getAchievementID(),0);
866
867 // 4J Stu - Some awards cause a menu to popup. This can be bad, especially if you are surrounded by mobs!
868 // We cannot pause the game unless in offline single player, but lets at least do it then
869 if( g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 && ProfileManager.GetAwardType(ach->getAchievementID() ) != eAwardType_Achievement )
870 {
871 ui.CloseUIScenes(m_iPad);
872 ui.NavigateToScene(m_iPad,eUIScene_PauseMenu);
873 }
874 }
875
876 // 4J-JEV: To stop spamming trophies.
877 unsigned long long achBit = ((unsigned long long)1) << ach->getAchievementID();
878 if ( !(achBit & m_awardedThisSession) )
879 {
880 ProfileManager.Award(m_iPad, ach->getAchievementID());
881 if (ProfileManager.IsFullVersion())
882 m_awardedThisSession |= achBit;
883 }
884 }
885 minecraft->stats[m_iPad]->award(stat, level->difficulty, count);
886 }
887 else
888 {
889 // 4J : WESTY : Added for new achievements.
890 StatsCounter* pStats = minecraft->stats[m_iPad];
891 pStats->award(stat, level->difficulty, count);
892
893 // 4J-JEV: Check achievements for unlocks.
894
895 // LEADER OF THE PACK
896 if ( stat == GenericStats::tamedEntity(eTYPE_WOLF) )
897 {
898 // Check to see if we have befriended 5 wolves! Is this really the best place to do this??!!
899 if ( pStats->getTotalValue(GenericStats::tamedEntity(eTYPE_WOLF)) >= 5 )
900 {
901 awardStat(GenericStats::leaderOfThePack(), GenericStats::param_noArgs());
902 }
903 }
904
905 // MOAR TOOLS
906 {
907 Stat *toolStats[4][5];
908 toolStats[0][0] = GenericStats::itemsCrafted(Item::shovel_wood->id);
909 toolStats[0][1] = GenericStats::itemsCrafted(Item::shovel_stone->id);
910 toolStats[0][2] = GenericStats::itemsCrafted(Item::shovel_iron->id);
911 toolStats[0][3] = GenericStats::itemsCrafted(Item::shovel_diamond->id);
912 toolStats[0][4] = GenericStats::itemsCrafted(Item::shovel_gold->id);
913 toolStats[1][0] = GenericStats::itemsCrafted(Item::pickAxe_wood->id);
914 toolStats[1][1] = GenericStats::itemsCrafted(Item::pickAxe_stone->id);
915 toolStats[1][2] = GenericStats::itemsCrafted(Item::pickAxe_iron->id);
916 toolStats[1][3] = GenericStats::itemsCrafted(Item::pickAxe_diamond->id);
917 toolStats[1][4] = GenericStats::itemsCrafted(Item::pickAxe_gold->id);
918 toolStats[2][0] = GenericStats::itemsCrafted(Item::hatchet_wood->id);
919 toolStats[2][1] = GenericStats::itemsCrafted(Item::hatchet_stone->id);
920 toolStats[2][2] = GenericStats::itemsCrafted(Item::hatchet_iron->id);
921 toolStats[2][3] = GenericStats::itemsCrafted(Item::hatchet_diamond->id);
922 toolStats[2][4] = GenericStats::itemsCrafted(Item::hatchet_gold->id);
923 toolStats[3][0] = GenericStats::itemsCrafted(Item::hoe_wood->id);
924 toolStats[3][1] = GenericStats::itemsCrafted(Item::hoe_stone->id);
925 toolStats[3][2] = GenericStats::itemsCrafted(Item::hoe_iron->id);
926 toolStats[3][3] = GenericStats::itemsCrafted(Item::hoe_diamond->id);
927 toolStats[3][4] = GenericStats::itemsCrafted(Item::hoe_gold->id);
928
929 bool justCraftedTool = false;
930 for (int i=0; i<4; i++)
931 {
932 for (int j=0; j<5; j++)
933 {
934 if ( stat == toolStats[i][j] )
935 {
936 justCraftedTool = true;
937 break;
938 }
939 }
940 }
941
942 if (justCraftedTool)
943 {
944 bool awardNow = true;
945 for (int i=0; i<4; i++)
946 {
947 bool craftedThisTool = false;
948 for (int j=0; j<5; j++)
949 {
950 if ( pStats->getTotalValue(toolStats[i][j]) > 0 )
951 craftedThisTool = true;
952 }
953
954 if (!craftedThisTool)
955 {
956 awardNow = false;
957 break;
958 }
959 }
960
961 if (awardNow)
962 {
963 awardStat(GenericStats::MOARTools(), GenericStats::param_noArgs());
964 }
965 }
966
967 }
968
969#ifdef _XBOX
970 // AWARD: Have we killed 10 creepers?
971 if ( pStats->getTotalValue( GenericStats::killsCreeper() ) >= 10 )
972 {
973 awardStat( GenericStats::kill10Creepers(), GenericStats::param_noArgs());
974 }
975
976 // AWARD : Have we been playing for 100 game days?
977 if ( pStats->getTotalValue( GenericStats::timePlayed() ) >= ( Level::TICKS_PER_DAY * 100 ) )
978 {
979 awardStat( GenericStats::play100Days(), GenericStats::param_noArgs());
980 }
981 // AWARD : Have we mined 100 blocks?
982 if ( pStats->getTotalValue( GenericStats::totalBlocksMined() ) >= 100 )
983 {
984 awardStat( GenericStats::mine100Blocks(), GenericStats::param_noArgs());
985 }
986#endif
987
988#ifdef _EXTENDED_ACHIEVEMENTS
989
990 // AWARD : Porkchop, cook and eat a porkchop.
991 {
992 Stat *cookPorkchop, *eatPorkchop;
993 cookPorkchop = GenericStats::itemsCrafted(Item::porkChop_cooked_Id);
994 eatPorkchop = GenericStats::itemsUsed(Item::porkChop_cooked_Id);
995
996 if ( stat == cookPorkchop || stat == eatPorkchop )
997 {
998 int numCookPorkchop, numEatPorkchop;
999 numCookPorkchop = pStats->getTotalValue(cookPorkchop);
1000 numEatPorkchop = pStats->getTotalValue(eatPorkchop);
1001
1002 app.DebugPrintf(
1003 "[AwardStat] Check unlock 'Porkchop': "
1004 "pork_cooked=%i, pork_eaten=%i.\n",
1005 numCookPorkchop, numEatPorkchop
1006 );
1007
1008 if ( (0 < numCookPorkchop) && (0 < numEatPorkchop) )
1009 {
1010 awardStat( GenericStats::porkChop(), GenericStats::param_porkChop() );
1011 }
1012 }
1013 }
1014
1015 // AWARD : Passing the Time, play for 100 minecraft days.
1016 {
1017 Stat *timePlayed = GenericStats::timePlayed();
1018
1019 if ( stat == timePlayed )
1020 {
1021 int iPlayedTicks, iRequiredTicks;
1022 iPlayedTicks = pStats->getTotalValue(timePlayed);
1023 iRequiredTicks = Level::TICKS_PER_DAY * 100;
1024
1025 /* app.DebugPrintf(
1026 "[AwardStat] Check unlock 'Passing the Time': "
1027 "total_ticks=%i, req=%i.\n",
1028 iPlayedTicks, iRequiredTicks
1029 ); */
1030
1031 if (iPlayedTicks >= iRequiredTicks)
1032 {
1033 awardStat( GenericStats::passingTheTime(), GenericStats::param_passingTheTime() );
1034 }
1035 }
1036 }
1037
1038 // AWARD : The Haggler, Acquire 30 emeralds.
1039 {
1040 Stat *emeraldMined, *emeraldBought;
1041 emeraldMined = GenericStats::blocksMined(Tile::emeraldOre_Id);
1042 emeraldBought = GenericStats::itemsBought(Item::emerald_Id);
1043
1044 if ( stat == emeraldMined || stat == emeraldBought )
1045 {
1046 int numEmeraldMined, numEmeraldBought, totalSum;
1047 numEmeraldMined = pStats->getTotalValue(emeraldMined);
1048 numEmeraldBought = pStats->getTotalValue(emeraldBought);
1049 totalSum = numEmeraldMined + numEmeraldBought;
1050
1051 app.DebugPrintf(
1052 "[AwardStat] Check unlock 'The Haggler': "
1053 "emerald_mined=%i, emerald_bought=%i, sum=%i.\n",
1054 numEmeraldMined, numEmeraldBought, totalSum
1055 );
1056
1057 if (totalSum >= 30) awardStat( GenericStats::theHaggler(), GenericStats::param_theHaggler() );
1058 }
1059 }
1060
1061 // AWARD : Pot Planter, craft and place a flowerpot.
1062 {
1063 Stat *craftFlowerpot, *placeFlowerpot;
1064 craftFlowerpot = GenericStats::itemsCrafted(Item::flowerPot_Id);
1065 placeFlowerpot = GenericStats::blocksPlaced(Tile::flowerPot_Id);
1066
1067 if ( stat == craftFlowerpot || stat == placeFlowerpot )
1068 {
1069 if ( (pStats->getTotalValue(craftFlowerpot) > 0) && (pStats->getTotalValue(placeFlowerpot) > 0) )
1070 {
1071 awardStat( GenericStats::potPlanter(), GenericStats::param_potPlanter() );
1072 }
1073 }
1074 }
1075
1076 // AWARD : It's a Sign, craft and place a sign.
1077 {
1078 Stat *craftSign, *placeWallsign, *placeSignpost;
1079 craftSign = GenericStats::itemsCrafted(Item::sign_Id);
1080 placeWallsign = GenericStats::blocksPlaced(Tile::wallSign_Id);
1081 placeSignpost = GenericStats::blocksPlaced(Tile::sign_Id);
1082
1083 if ( stat == craftSign || stat == placeWallsign || stat == placeSignpost )
1084 {
1085 int numCraftedSigns, numPlacedWallSign, numPlacedSignpost;
1086 numCraftedSigns = pStats->getTotalValue(craftSign);
1087 numPlacedWallSign = pStats->getTotalValue(placeWallsign);
1088 numPlacedSignpost = pStats->getTotalValue(placeSignpost);
1089
1090 app.DebugPrintf(
1091 "[AwardStat] Check unlock 'It's a Sign': "
1092 "crafted=%i, placedWallSigns=%i, placedSignposts=%i.\n",
1093 numCraftedSigns, numPlacedWallSign, numPlacedSignpost
1094 );
1095
1096 if ( (numCraftedSigns>0) && ((numPlacedWallSign+numPlacedSignpost)>0) )
1097 {
1098 awardStat( GenericStats::itsASign(), GenericStats::param_itsASign());
1099 }
1100 }
1101 }
1102
1103 // AWARD : Rainbow Collection, collect all different colours of wool.
1104 {
1105 bool justPickedupWool = false;
1106
1107 for (int i=0; i<16; i++)
1108 if ( stat == GenericStats::itemsCollected(Tile::wool_Id, i) )
1109 justPickedupWool = true;
1110
1111 if (justPickedupWool)
1112 {
1113 unsigned int woolCount = 0;
1114
1115 for (unsigned int i = 0; i < 16; i++)
1116 {
1117 if (pStats->getTotalValue(GenericStats::itemsCollected(Tile::wool_Id, i)) > 0)
1118 woolCount++;
1119 }
1120
1121 if (woolCount >= 16) awardStat( GenericStats::rainbowCollection(), GenericStats::param_rainbowCollection() );
1122 }
1123 }
1124
1125 // AWARD : Adventuring Time, visit at least 17 biomes
1126 {
1127 bool justEnteredBiome = false;
1128
1129 for (int i=0; i<23; i++)
1130 if ( stat == GenericStats::enteredBiome(i) )
1131 justEnteredBiome = true;
1132
1133 if (justEnteredBiome)
1134 {
1135 unsigned int biomeCount = 0;
1136
1137 for (unsigned int i = 0; i < 23; i++)
1138 {
1139 if (pStats->getTotalValue(GenericStats::enteredBiome(i)) > 0)
1140 biomeCount++;
1141 }
1142
1143 if (biomeCount >= 17) awardStat( GenericStats::adventuringTime(), GenericStats::param_adventuringTime() );
1144 }
1145 }
1146#endif
1147 }
1148#endif
1149}
1150
1151bool LocalPlayer::isSolidBlock(int x, int y, int z)
1152{
1153 return level->isSolidBlockingTile(x, y, z);
1154}
1155
1156bool LocalPlayer::checkInTile(double x, double y, double z)
1157{
1158 int xTile = Mth::floor(x);
1159 int yTile = Mth::floor(y);
1160 int zTile = Mth::floor(z);
1161
1162 double xd = x - xTile;
1163 double zd = z - zTile;
1164
1165 if (isSolidBlock(xTile, yTile, zTile) || isSolidBlock(xTile, yTile + 1, zTile))
1166 {
1167 bool west = !isSolidBlock(xTile - 1, yTile, zTile) && !isSolidBlock(xTile - 1, yTile + 1, zTile);
1168 bool east = !isSolidBlock(xTile + 1, yTile, zTile) && !isSolidBlock(xTile + 1, yTile + 1, zTile);
1169 bool north = !isSolidBlock(xTile, yTile, zTile - 1) && !isSolidBlock(xTile, yTile + 1, zTile - 1);
1170 bool south = !isSolidBlock(xTile, yTile, zTile + 1) && !isSolidBlock(xTile, yTile + 1, zTile + 1);
1171
1172 int dir = -1;
1173 double closest = 9999;
1174 if (west && xd < closest)
1175 {
1176 closest = xd;
1177 dir = 0;
1178 }
1179 if (east && 1 - xd < closest)
1180 {
1181 closest = 1 - xd;
1182 dir = 1;
1183 }
1184 if (north && zd < closest)
1185 {
1186 closest = zd;
1187 dir = 4;
1188 }
1189 if (south && 1 - zd < closest)
1190 {
1191 closest = 1 - zd;
1192 dir = 5;
1193 }
1194
1195 float speed = 0.1f;
1196 if (dir == 0) this->xd = -speed;
1197 if (dir == 1) this->xd = +speed;
1198 if (dir == 4) this->zd = -speed;
1199 if (dir == 5) this->zd = +speed;
1200 }
1201
1202 return false;
1203
1204}
1205
1206void LocalPlayer::setSprinting(bool value)
1207{
1208 Player::setSprinting(value);
1209 if (value == false) sprintTime = 0;
1210 else sprintTime = SPRINT_DURATION;
1211}
1212
1213void LocalPlayer::setExperienceValues(float experienceProgress, int totalExp, int experienceLevel)
1214{
1215 this->experienceProgress = experienceProgress;
1216 this->totalExperience = totalExp;
1217 this->experienceLevel = experienceLevel;
1218}
1219
1220// 4J: removed
1221//void LocalPlayer::sendMessage(ChatMessageComponent *message)
1222//{
1223// minecraft->gui->getChat()->addMessage(message.toString(true));
1224//}
1225
1226Pos LocalPlayer::getCommandSenderWorldPosition()
1227{
1228 return new Pos(floor(x + .5), floor(y + .5), floor(z + .5));
1229}
1230
1231shared_ptr<ItemInstance> LocalPlayer::getCarriedItem()
1232{
1233 return inventory->getSelected();
1234}
1235
1236void LocalPlayer::playSound(int soundId, float volume, float pitch)
1237{
1238 level->playLocalSound(x, y - heightOffset, z, soundId, volume, pitch, false);
1239}
1240
1241bool LocalPlayer::isRidingJumpable()
1242{
1243 return riding != NULL && riding->GetType() == eTYPE_HORSE;
1244}
1245
1246float LocalPlayer::getJumpRidingScale()
1247{
1248 return jumpRidingScale;
1249}
1250
1251void LocalPlayer::sendRidingJump()
1252{
1253}
1254
1255bool LocalPlayer::hasPermission(EGameCommand command)
1256{
1257 return level->getLevelData()->getAllowCommands();
1258}
1259
1260void LocalPlayer::onCrafted(shared_ptr<ItemInstance> item)
1261{
1262 if( minecraft->localgameModes[m_iPad] != NULL )
1263 {
1264 TutorialMode *gameMode = (TutorialMode *)minecraft->localgameModes[m_iPad];
1265 gameMode->getTutorial()->onCrafted(item);
1266 }
1267}
1268
1269void LocalPlayer::setAndBroadcastCustomSkin(DWORD skinId)
1270{
1271 setCustomSkin(skinId);
1272}
1273
1274void LocalPlayer::setAndBroadcastCustomCape(DWORD capeId)
1275{
1276 setCustomCape(capeId);
1277}
1278
1279// 4J TODO - Remove
1280#include "..\Minecraft.World\LevelChunk.h"
1281void LocalPlayer::mapPlayerChunk(const unsigned int flagTileType)
1282{
1283 int cx = this->xChunk;
1284 int cz = this->zChunk;
1285
1286 int pZ = ((int) floor(this->z)) %16;
1287 int pX = ((int) floor(this->x)) %16;
1288
1289 cout<<"player in chunk ("<<cx<<","<<cz<<") at ("
1290 <<this->x<<","<<this->y<<","<<this->z<<")\n";
1291
1292 for (int v = -1; v < 2; v++)
1293 for (unsigned int z = 0; z < 16; z++)
1294 {
1295 for (int u = -1; u < 2; u++)
1296 for (unsigned int x = 0; x < 16; x++)
1297 {
1298 LevelChunk *cc = level->getChunk(cx+u, cz+v);
1299 if ( x==pX && z==pZ && u==0 && v==0)
1300 cout << "O";
1301 else for (unsigned int y = 127; y > 0; y--)
1302 {
1303 int t = cc->getTile(x,y,z);
1304 if (flagTileType != 0 && t == flagTileType) { cout << "@"; break; }
1305 else if (t != 0 && t < 10) { cout << t; break; }
1306 else if (t > 0) { cout << "#"; break; }
1307 }
1308 }
1309 cout << "\n";
1310 }
1311
1312 cout << "\n";
1313}
1314
1315
1316void LocalPlayer::handleMouseDown(int button, bool down)
1317{
1318 // 4J Stu - We should not accept any input while asleep, except the above to wake up
1319 if(isSleeping() && level != NULL && level->isClientSide)
1320 {
1321 return;
1322 }
1323 if (!down) missTime = 0;
1324 if (button == 0 && missTime > 0) return;
1325
1326 if (down && minecraft->hitResult != NULL && minecraft->hitResult->type == HitResult::TILE && button == 0)
1327 {
1328 int x = minecraft->hitResult->x;
1329 int y = minecraft->hitResult->y;
1330 int z = minecraft->hitResult->z;
1331
1332 // 4J - addition to stop layer mining out of the top or bottom of the world
1333 // 4J Stu - Allow this for The End
1334 if( ( ( y == 0 ) || ( ( y == 127 ) && level->dimension->hasCeiling ) ) && level->dimension->id != 1 ) return;
1335
1336 minecraft->gameMode->continueDestroyBlock(x, y, z, minecraft->hitResult->f);
1337
1338 if(mayDestroyBlockAt(x,y,z))
1339 {
1340 minecraft->particleEngine->crack(x, y, z, minecraft->hitResult->f);
1341 swing();
1342 }
1343 }
1344 else
1345 {
1346 minecraft->gameMode->stopDestroyBlock();
1347 }
1348}
1349
1350bool LocalPlayer::creativeModeHandleMouseClick(int button, bool buttonPressed)
1351{
1352 if( buttonPressed )
1353 {
1354 if( lastClickState == lastClick_oldRepeat )
1355 {
1356 return false;
1357 }
1358
1359 // Are we in an auto-repeat situation? - If so only tell the game that we've clicked if we move more than a unit away from our last
1360 // click position in any axis
1361 if( lastClickState != lastClick_invalid )
1362 {
1363 // If we're in disabled mode already (set when sprinting) then don't do anything - if we're sprinting, we don't auto-repeat at all.
1364 // With auto repeat on, we can quickly place fires causing photosensitivity issues due to rapid flashing
1365 if( lastClickState == lastClick_disabled ) return false;
1366 // If we've started sprinting, go into this mode & also don't do anything
1367 // Ignore repeate when sleeping
1368 if( isSprinting() )
1369 {
1370 lastClickState = lastClick_disabled;
1371 return false;
1372 }
1373
1374 // Get distance from last click point in each axis
1375 float dX = (float)x - lastClickX;
1376 float dY = (float)y - lastClickY;
1377 float dZ = (float)z - lastClickZ;
1378 bool newClick = false;
1379
1380 float ddx = dX - lastClickdX;
1381 float ddy = dY - lastClickdY;
1382 float ddz = dZ - lastClickdZ;
1383
1384 if( lastClickState == lastClick_moving )
1385 {
1386 float deltaChange = sqrtf(ddx * ddx + ddy * ddy + ddz * ddz );
1387 if( deltaChange < 0.01f )
1388 {
1389 lastClickState = lastClick_stopped;
1390 lastClickTolerance = 0.0f;
1391 }
1392 }
1393 else if( lastClickState == lastClick_stopped )
1394 {
1395 float deltaChange = sqrtf(ddx * ddx + ddy * ddy + ddz * ddz );
1396 if( deltaChange >= 0.01f )
1397 {
1398 lastClickState = lastClick_moving;
1399 lastClickTolerance = 0.0f;
1400 }
1401 else
1402 {
1403 lastClickTolerance += 0.1f;
1404 if( lastClickTolerance > 0.7f )
1405 {
1406 lastClickTolerance = 0.0f;
1407 lastClickState = lastClick_init;
1408 }
1409 }
1410 }
1411
1412 lastClickdX = dX;
1413 lastClickdY = dY;
1414 lastClickdZ = dZ;
1415
1416 // If we have moved more than one unit in any one axis, then register a new click
1417 // The new click position is normalised at one unit in the direction of movement, so that we don't gradually drift away if we detect the movement a fraction over
1418 // the unit distance each time
1419
1420 if( fabsf(dX) >= 1.0f )
1421 {
1422 dX= ( dX < 0.0f ) ? ceilf(dX) : floorf(dX);
1423 newClick = true;
1424 }
1425 else if( fabsf(dY) >= 1.0f )
1426 {
1427 dY= ( dY < 0.0f ) ? ceilf(dY) : floorf(dY);
1428 newClick = true;
1429 }
1430 else if( fabsf(dZ) >= 1.0f )
1431 {
1432 dZ= ( dZ < 0.0f ) ? ceilf(dZ) : floorf(dZ);
1433 newClick = true;
1434 }
1435
1436 if( ( !newClick ) && ( lastClickTolerance > 0.0f ) )
1437 {
1438 float fTarget = 1.0f - lastClickTolerance;
1439
1440 if( fabsf(dX) >= fTarget ) newClick = true;
1441 if( fabsf(dY) >= fTarget ) newClick = true;
1442 if( fabsf(dZ) >= fTarget ) newClick = true;
1443 }
1444
1445 if( newClick )
1446 {
1447 lastClickX += dX;
1448 lastClickY += dY;
1449 lastClickZ += dZ;
1450
1451 // Get a more accurate pick from the position where the new click should ideally have come from, rather than
1452 // where we happen to be now (ie a rounded number of units from the last Click position)
1453 double oldX = x;
1454 double oldY = y;
1455 double oldZ = z;
1456 x = lastClickX;
1457 y = lastClickY;
1458 z = lastClickZ;
1459
1460 minecraft->gameRenderer->pick(1);
1461
1462 x = oldX;
1463 y = oldY;
1464 z = oldZ;
1465
1466 handleMouseClick(button);
1467
1468 if( lastClickState == lastClick_stopped )
1469 {
1470 lastClickState = lastClick_init;
1471 lastClickTolerance = 0.0f;
1472 }
1473 else
1474 {
1475 lastClickState = lastClick_moving;
1476 lastClickTolerance = 0.0f;
1477 }
1478 }
1479 }
1480 else
1481 {
1482 // First click - just record position & handle
1483 lastClickX = (float)x;
1484 lastClickY = (float)y;
1485 lastClickZ = (float)z;
1486 // If we actually placed an item, then move into the init state as we are going to be doing the special creative mode auto repeat
1487 bool itemPlaced = handleMouseClick(button);
1488 // If we're sprinting or riding, don't auto-repeat at all. With auto repeat on, we can quickly place fires causing photosensitivity issues due to rapid flashing
1489 // Also ignore repeats when the player is sleeping
1490 if( isSprinting() || isRiding() || isSleeping() )
1491 {
1492 lastClickState = lastClick_disabled;
1493 }
1494 else
1495 {
1496 if( itemPlaced )
1497 {
1498 lastClickState = lastClick_init;
1499 lastClickTolerance = 0.0f;
1500 }
1501 else
1502 {
1503 // Didn't place an item - might actually be activating a switch or door or something - just do a standard auto repeat in this case
1504 lastClickState = lastClick_oldRepeat;
1505 }
1506 }
1507 return true;
1508 }
1509 }
1510 else
1511 {
1512 lastClickState = lastClick_invalid;
1513 }
1514 return false;
1515
1516}
1517
1518bool LocalPlayer::handleMouseClick(int button)
1519{
1520 bool returnItemPlaced = false;
1521
1522 if (button == 0 && missTime > 0) return false;
1523 if (button == 0)
1524 {
1525 //app.DebugPrintf("handleMouseClick - Player %d is swinging\n",GetXboxPad());
1526 swing();
1527 }
1528
1529 bool mayUse = true;
1530
1531 // 4J-PB - Adding a special case in here for sleeping in a bed in a multiplayer game - we need to wake up, and we don't have the inbedchatscreen with a button
1532
1533 if(button==1 && (isSleeping() && level != NULL && level->isClientSide))
1534 {
1535 if(lastClickState == lastClick_oldRepeat) return false;
1536
1537
1538 shared_ptr<MultiplayerLocalPlayer> mplp = dynamic_pointer_cast<MultiplayerLocalPlayer>( shared_from_this() );
1539
1540 if(mplp && mplp->connection) mplp->StopSleeping();
1541
1542 }
1543 // 4J Stu - We should not accept any input while asleep, except the above to wake up
1544 if(isSleeping() && level != NULL && level->isClientSide)
1545 {
1546 return false;
1547 }
1548
1549 shared_ptr<ItemInstance> oldItem = inventory->getSelected();
1550
1551 if (minecraft->hitResult == NULL)
1552 {
1553 if (button == 0 && minecraft->localgameModes[GetXboxPad()]->hasMissTime()) missTime = 10;
1554 }
1555 else if (minecraft->hitResult->type == HitResult::ENTITY)
1556 {
1557 if (button == 0)
1558 {
1559 minecraft->gameMode->attack(minecraft->localplayers[GetXboxPad()], minecraft->hitResult->entity);
1560 }
1561 if (button == 1)
1562 {
1563 // 4J-PB - if we milk a cow here, and end up with a bucket of milk, the if (mayUse && button == 1) further down will
1564 // then empty our bucket if we're pointing at a tile
1565 // It looks like interact really should be returning a result so we can check this, but it's possibly just the
1566 // milk bucket that causes a problem
1567
1568 if(minecraft->hitResult->entity->GetType()==eTYPE_COW)
1569 {
1570 // If I have an empty bucket in my hand, it's going to be filled with milk, so turn off mayUse
1571 shared_ptr<ItemInstance> item = inventory->getSelected();
1572 if(item && (item->id==Item::bucket_empty_Id))
1573 {
1574 mayUse=false;
1575 }
1576 }
1577 if( minecraft->gameMode->interact(minecraft->localplayers[GetXboxPad()], minecraft->hitResult->entity) )
1578 {
1579 mayUse = false;
1580 }
1581 }
1582 }
1583 else if (minecraft->hitResult->type == HitResult::TILE)
1584 {
1585 int x = minecraft->hitResult->x;
1586 int y = minecraft->hitResult->y;
1587 int z = minecraft->hitResult->z;
1588 int face = minecraft->hitResult->f;
1589
1590 if (button == 0)
1591 {
1592 // 4J - addition to stop layer mining out of the top or bottom of the world
1593 // 4J Stu - Allow this for The End
1594 if( !( ( y == 0 ) || ( ( y == 127 ) && level->dimension->hasCeiling ) ) || level->dimension->id == 1 )
1595 {
1596 minecraft->gameMode->startDestroyBlock(x, y, z, minecraft->hitResult->f);
1597 }
1598 }
1599 else
1600 {
1601 shared_ptr<ItemInstance> item = oldItem;
1602 int oldCount = item != NULL ? item->count : 0;
1603 bool usedItem = false;
1604 if (minecraft->gameMode->useItemOn(minecraft->localplayers[GetXboxPad()], level, item, x, y, z, face, minecraft->hitResult->pos, false, &usedItem))
1605 {
1606 // Presume that if we actually used the held item, then we've placed it
1607 if( usedItem )
1608 {
1609 returnItemPlaced = true;
1610 }
1611 mayUse = false;
1612 //app.DebugPrintf("Player %d is swinging\n",GetXboxPad());
1613 swing();
1614 }
1615 if (item == NULL)
1616 {
1617 return false;
1618 }
1619
1620 if (item->count == 0)
1621 {
1622 inventory->items[inventory->selected] = nullptr;
1623 }
1624 else if (item->count != oldCount || minecraft->localgameModes[GetXboxPad()]->hasInfiniteItems())
1625 {
1626 minecraft->gameRenderer->itemInHandRenderer->itemPlaced();
1627 }
1628 }
1629 }
1630
1631 if (mayUse && button == 1)
1632 {
1633 shared_ptr<ItemInstance> item = inventory->getSelected();
1634 if (item != NULL)
1635 {
1636 if (minecraft->gameMode->useItem(minecraft->localplayers[GetXboxPad()], level, item))
1637 {
1638 minecraft->gameRenderer->itemInHandRenderer->itemUsed();
1639 }
1640 }
1641 }
1642 return returnItemPlaced;
1643}
1644
1645void LocalPlayer::updateRichPresence()
1646{
1647 if((m_iPad!=-1)/* && !ui.GetMenuDisplayed(m_iPad)*/ )
1648 {
1649 shared_ptr<ItemInstance> selectedItem = inventory->getSelected();
1650 if(selectedItem != NULL && selectedItem->id == Item::fishingRod_Id)
1651 {
1652 app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_FISHING);
1653 }
1654 else if(selectedItem != NULL && selectedItem->id == Item::map_Id)
1655 {
1656 app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_MAP);
1657 }
1658 else if ( (riding != NULL) && riding->instanceof(eTYPE_MINECART) )
1659 {
1660 app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_RIDING_MINECART);
1661 }
1662 else if ( (riding != NULL) && riding->instanceof(eTYPE_BOAT) )
1663 {
1664 app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_BOATING);
1665 }
1666 else if ( (riding != NULL) && riding->instanceof(eTYPE_PIG) )
1667 {
1668 app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_RIDING_PIG);
1669 }
1670 else if( this->dimension == -1 )
1671 {
1672 app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_NETHER);
1673 }
1674 else if( minecraft->soundEngine->GetIsPlayingStreamingCDMusic() )
1675 {
1676 app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_CD);
1677 }
1678 else
1679 {
1680 app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_BLANK);
1681 }
1682 }
1683}
1684
1685// 4J Stu - Added for telemetry
1686void LocalPlayer::SetSessionTimerStart(void)
1687{
1688 m_sessionTimeStart=app.getAppTime();
1689 m_dimensionTimeStart=m_sessionTimeStart;
1690}
1691
1692float LocalPlayer::getSessionTimer(void)
1693{
1694 return app.getAppTime()-m_sessionTimeStart;
1695}
1696
1697float LocalPlayer::getAndResetChangeDimensionTimer()
1698{
1699 float appTime = app.getAppTime();
1700 float returnVal = appTime - m_dimensionTimeStart;
1701 m_dimensionTimeStart = appTime;
1702 return returnVal;
1703}
1704
1705void LocalPlayer::handleCollectItem(shared_ptr<ItemInstance> item)
1706{
1707 if(item != NULL)
1708 {
1709 unsigned int itemCountAnyAux = 0;
1710 unsigned int itemCountThisAux = 0;
1711 for (unsigned int k = 0; k < inventory->items.length; ++k)
1712 {
1713 if (inventory->items[k] != NULL)
1714 {
1715 // do they have the item
1716 if(inventory->items[k]->id == item->id)
1717 {
1718 unsigned int quantity = inventory->items[k]->GetCount();
1719
1720 itemCountAnyAux += quantity;
1721
1722 if( inventory->items[k]->getAuxValue() == item->getAuxValue() )
1723 {
1724 itemCountThisAux += quantity;
1725 }
1726 }
1727 }
1728 }
1729 TutorialMode *gameMode = (TutorialMode *)minecraft->localgameModes[m_iPad];
1730 gameMode->getTutorial()->onTake(item, itemCountAnyAux, itemCountThisAux);
1731 }
1732
1733 if(ui.IsContainerMenuDisplayed(m_iPad))
1734 {
1735 ui.HandleInventoryUpdated(m_iPad);
1736 }
1737}
1738
1739void LocalPlayer::SetPlayerAdditionalModelParts(vector<ModelPart *>pAdditionalModelParts)
1740{
1741 m_pAdditionalModelParts=pAdditionalModelParts;
1742}