the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 565 lines 14 kB view raw
1#include "stdafx.h" 2#include "net.minecraft.world.level.h" 3#include "net.minecraft.world.level.tile.h" 4#include "net.minecraft.world.entity.h" 5#include "net.minecraft.world.entity.player.h" 6#include "net.minecraft.world.phys.h" 7#include "net.minecraft.world.item.h" 8#include "net.minecraft.world.damagesource.h" 9#include "net.minecraft.world.item.enchantment.h" 10#include "net.minecraft.network.packet.h" 11#include "..\Minecraft.Client\ServerPlayer.h" 12#include "..\Minecraft.Client\PlayerConnection.h" 13#include "com.mojang.nbt.h" 14#include "Arrow.h" 15 16// 4J : WESTY : Added for other award, kill creeper with arrow. 17#include "net.minecraft.world.entity.monster.h" 18#include "net.minecraft.stats.h" 19#include "SoundTypes.h" 20 21 22 23// base damage, multiplied with velocity 24const double Arrow::ARROW_BASE_DAMAGE = 2.0f; 25 26// 4J - added common ctor code. 27void Arrow::_init() 28{ 29 // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that 30 // the derived version of the function is called 31 this->defineSynchedData(); 32 33 xTile = -1; 34 yTile = -1; 35 zTile = -1; 36 lastTile = 0; 37 lastData = 0; 38 inGround = false; 39 pickup = PICKUP_DISALLOWED; 40 shakeTime = 0; 41 flightTime = 0; 42 43 owner = nullptr; 44 life = 0; 45 46 baseDamage = ARROW_BASE_DAMAGE; 47 knockback = 0; 48} 49 50 51Arrow::Arrow(Level *level) : Entity( level ) 52{ 53 _init(); 54 55 viewScale = 10; 56 setSize(0.5f, 0.5f); 57} 58 59Arrow::Arrow(Level *level, shared_ptr<LivingEntity> mob, shared_ptr<LivingEntity> target, float power, float uncertainty) : Entity( level ) 60{ 61 _init(); 62 63 viewScale = 10; 64 owner = mob; 65 if ( mob->instanceof(eTYPE_PLAYER) ) pickup = PICKUP_ALLOWED; 66 67 y = mob->y + mob->getHeadHeight() - 0.1f; 68 69 double xd = target->x - mob->x; 70 double yd = (target->y + target->getHeadHeight() - 0.7f) - y; 71 double zd = target->z - mob->z; 72 double sd = sqrt(xd * xd + zd * zd); 73 if (sd < 0.0000001) return; 74 75 float yRot = (float) (atan2(zd, xd) * 180 / PI) - 90; 76 float xRot = (float) -(atan2(yd, sd) * 180 / PI); 77 78 double xdn = xd / sd; 79 double zdn = zd / sd; 80 moveTo(mob->x + xdn, y, mob->z + zdn, yRot, xRot); 81 heightOffset = 0; 82 83 float yo = (float) sd * 0.2f; 84 shoot(xd, yd + yo, zd, power, uncertainty); 85} 86 87Arrow::Arrow(Level *level, double x, double y, double z) : Entity( level ) 88{ 89 _init(); 90 91 viewScale = 10; 92 setSize(0.5f, 0.5f); 93 94 setPos(x, y, z); 95 heightOffset = 0; 96} 97 98Arrow::Arrow(Level *level, shared_ptr<LivingEntity> mob, float power) : Entity( level ) 99{ 100 _init(); 101 102 viewScale = 10; 103 owner = mob; 104 if ( mob->instanceof(eTYPE_PLAYER) ) pickup = PICKUP_ALLOWED; 105 106 setSize(0.5f, 0.5f); 107 108 moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot); 109 110 x -= Mth::cos(yRot / 180 * PI) * 0.16f; 111 y -= 0.1f; 112 z -= Mth::sin(yRot / 180 * PI) * 0.16f; 113 setPos(x, y, z); 114 heightOffset = 0; 115 116 xd = -Mth::sin(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI); 117 zd = Mth::cos(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI); 118 yd = -Mth::sin(xRot / 180 * PI); 119 120 shoot(xd, yd, zd, power * 1.5f, 1); 121} 122 123 124void Arrow::defineSynchedData() 125{ 126 entityData->define(ID_FLAGS, (byte) 0); 127} 128 129 130void Arrow::shoot(double xd, double yd, double zd, float pow, float uncertainty) 131{ 132 float dist = (float) sqrt(xd * xd + yd * yd + zd * zd); 133 134 xd /= dist; 135 yd /= dist; 136 zd /= dist; 137 138 xd += (random->nextGaussian() * (random->nextBoolean() ? -1 : 1)) * 0.0075f * uncertainty; 139 yd += (random->nextGaussian() * (random->nextBoolean() ? -1 : 1)) * 0.0075f * uncertainty; 140 zd += (random->nextGaussian() * (random->nextBoolean() ? -1 : 1)) * 0.0075f * uncertainty; 141 142 xd *= pow; 143 yd *= pow; 144 zd *= pow; 145 146 this->xd = xd; 147 this->yd = yd; 148 this->zd = zd; 149 150 double sd = sqrt(xd * xd + zd * zd); 151 152 yRotO = yRot = (float) (atan2(xd, zd) * 180 / PI); 153 xRotO = xRot = (float) (atan2(yd, sd) * 180 / PI); 154 life = 0; 155} 156 157void Arrow::lerpTo(double x, double y, double z, float yRot, float xRot, int steps) 158{ 159 setPos(x, y, z); 160 setRot(yRot, xRot); 161} 162 163void Arrow::lerpMotion(double xd, double yd, double zd) 164{ 165 this->xd = xd; 166 this->yd = yd; 167 this->zd = zd; 168 if (xRotO == 0 && yRotO == 0) 169 { 170 double sd = sqrt(xd * xd + zd * zd); 171 yRotO = yRot = (float) (atan2( xd, zd) * 180 / PI); 172 xRotO = xRot = (float) (atan2( yd, sd) * 180 / PI); 173 xRotO = xRot; 174 yRotO = yRot; 175 app.DebugPrintf("%f %f : 0x%x\n",xRot,yRot,&yRot); 176 moveTo(x, y, z, yRot, xRot); 177 life = 0; 178 } 179} 180 181void Arrow::tick() 182{ 183 Entity::tick(); 184 185 186 if (xRotO == 0 && yRotO == 0) 187 { 188 double sd = sqrt(xd * xd + zd * zd); 189 yRotO = yRot = (float) (atan2(xd, zd) * 180 / PI); 190 xRotO = xRot = (float) (atan2(yd, sd) * 180 / PI); 191 } 192 193 194 { 195 int t = level->getTile(xTile, yTile, zTile); 196 if (t > 0) 197 { 198 Tile::tiles[t]->updateShape(level, xTile, yTile, zTile); 199 AABB *aabb = Tile::tiles[t]->getAABB(level, xTile, yTile, zTile); 200 if (aabb != NULL && aabb->contains(Vec3::newTemp(x, y, z))) 201 { 202 inGround = true; 203 } 204 } 205 206 } 207 208 if (shakeTime > 0) shakeTime--; 209 210 if (inGround) 211 { 212 int tile = level->getTile(xTile, yTile, zTile); 213 int data = level->getData(xTile, yTile, zTile); 214 if (tile != lastTile || data != lastData) 215 { 216 inGround = false; 217 218 xd *= random->nextFloat() * 0.2f; 219 yd *= random->nextFloat() * 0.2f; 220 zd *= random->nextFloat() * 0.2f; 221 life = 0; 222 flightTime = 0; 223 return; 224 } 225 226 else 227 { 228 life++; 229 if (life == 20 * 60) remove(); 230 return; 231 } 232 } 233 234 else 235 { 236 flightTime++; 237 } 238 239 Vec3 *from = Vec3::newTemp(x, y, z); 240 Vec3 *to = Vec3::newTemp(x + xd, y + yd, z + zd); 241 HitResult *res = level->clip(from, to, false, true); 242 243 from = Vec3::newTemp(x, y, z); 244 to = Vec3::newTemp(x + xd, y + yd, z + zd); 245 if (res != NULL) 246 { 247 to = Vec3::newTemp(res->pos->x, res->pos->y, res->pos->z); 248 } 249 shared_ptr<Entity> hitEntity = nullptr; 250 vector<shared_ptr<Entity> > *objects = level->getEntities(shared_from_this(), this->bb->expand(xd, yd, zd)->grow(1, 1, 1)); 251 double nearest = 0; 252 AUTO_VAR(itEnd, objects->end()); 253 for (AUTO_VAR(it, objects->begin()); it != itEnd; it++) 254 { 255 shared_ptr<Entity> e = *it; //objects->at(i); 256 if (!e->isPickable() || (e == owner && flightTime < 5)) continue; 257 258 float rr = 0.3f; 259 AABB *bb = e->bb->grow(rr, rr, rr); 260 HitResult *p = bb->clip(from, to); 261 if (p != NULL) 262 { 263 double dd = from->distanceTo(p->pos); 264 if (dd < nearest || nearest == 0) 265 { 266 hitEntity = e; 267 nearest = dd; 268 } 269 delete p; 270 } 271 } 272 273 if (hitEntity != NULL) 274 { 275 delete res; 276 res = new HitResult(hitEntity); 277 } 278 279 if ( (res != NULL) && (res->entity != NULL) && res->entity->instanceof(eTYPE_PLAYER)) 280 { 281 shared_ptr<Player> player = dynamic_pointer_cast<Player>(res->entity); 282 // 4J: Check for owner being null 283 if ( player->abilities.invulnerable || ((owner != NULL) && (owner->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast<Player>(owner)->canHarmPlayer(player)))) 284 { 285 res = NULL; 286 } 287 } 288 289 if (res != NULL) 290 { 291 if (res->entity != NULL) 292 { 293 float pow = Mth::sqrt(xd * xd + yd * yd + zd * zd); 294 int dmg = (int) Mth::ceil((float)(pow * baseDamage)); 295 296 if(isCritArrow()) dmg += random->nextInt(dmg / 2 + 2); 297 298 DamageSource *damageSource = NULL; 299 if (owner == NULL) 300 { 301 damageSource = DamageSource::arrow(dynamic_pointer_cast<Arrow>(shared_from_this()), shared_from_this()); 302 } 303 else 304 { 305 damageSource = DamageSource::arrow(dynamic_pointer_cast<Arrow>(shared_from_this()), owner); 306 } 307 308 if(res->entity->hurt(damageSource, dmg)) 309 { 310 // Firx for #67839 - Customer Encountered: Bows enchanted with "Flame" still set things on fire if pvp/attack animals is turned off 311 // 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) 312 // set targets on fire first because we want cooked 313 // pork/chicken/steak 314 if (isOnFire() && res->entity->GetType() != eTYPE_ENDERMAN) 315 { 316 res->entity->setOnFire(5); 317 } 318 319 if (res->entity->instanceof(eTYPE_LIVINGENTITY)) 320 { 321 shared_ptr<LivingEntity> mob = dynamic_pointer_cast<LivingEntity>(res->entity); 322 323 if (!level->isClientSide) 324 { 325 mob->setArrowCount(mob->getArrowCount() + 1); 326 } 327 if (knockback > 0) 328 { 329 float pushLen = sqrt(xd * xd + zd * zd); 330 if (pushLen > 0) 331 { 332 res->entity->push(xd * knockback * .6f / pushLen, 0.1, zd * knockback * .6f / pushLen); 333 } 334 } 335 336 if (owner != NULL) 337 { 338 ThornsEnchantment::doThornsAfterAttack(owner, mob, random); 339 } 340 341 if (owner != NULL && res->entity != owner && owner->GetType() == eTYPE_SERVERPLAYER) 342 { 343 dynamic_pointer_cast<ServerPlayer>(owner)->connection->send( shared_ptr<GameEventPacket>( new GameEventPacket(GameEventPacket::SUCCESSFUL_BOW_HIT, 0)) ); 344 } 345 } 346 347 // 4J : WESTY : For award, need to track if creeper was killed by arrow from the player. 348 if (owner != NULL && owner->instanceof(eTYPE_PLAYER) // arrow owner is a player 349 && !res->entity->isAlive() // target is now dead 350 && (res->entity->GetType() == eTYPE_CREEPER)) // target is a creeper 351 352 { 353 dynamic_pointer_cast<Player>(owner)->awardStat( 354 GenericStats::arrowKillCreeper(), 355 GenericStats::param_arrowKillCreeper() 356 ); 357 } 358 359 playSound( eSoundType_RANDOM_BOW_HIT, 1.0f, 1.2f / (random->nextFloat() * 0.2f + 0.9f)); 360 if (res->entity->GetType() != eTYPE_ENDERDRAGON) remove(); 361 } 362 else 363 { 364 xd *= -0.1f; 365 yd *= -0.1f; 366 zd *= -0.1f; 367 yRot += 180; 368 yRotO += 180; 369 flightTime = 0; 370 } 371 372 delete damageSource; 373 } 374 else 375 { 376 xTile = res->x; 377 yTile = res->y; 378 zTile = res->z; 379 lastTile = level->getTile(xTile, yTile, zTile); 380 lastData = level->getData(xTile, yTile, zTile); 381 xd = (float) (res->pos->x - x); 382 yd = (float) (res->pos->y - y); 383 zd = (float) (res->pos->z - z); 384 float dd = (float) sqrt(xd * xd + yd * yd + zd * zd); 385 // 4J added check - zero dd here was creating NaNs 386 if( dd > 0.0001f ) 387 { 388 x -= (xd / dd) * 0.05f; 389 y -= (yd / dd) * 0.05f; 390 z -= (zd / dd) * 0.05f; 391 } 392 393 playSound(eSoundType_RANDOM_BOW_HIT, 1.0f, 1.2f / (random->nextFloat() * 0.2f + 0.9f)); 394 inGround = true; 395 shakeTime = 7; 396 setCritArrow(false); 397 398 if (lastTile != 0) 399 { 400 Tile::tiles[lastTile]->entityInside(level, xTile, yTile, zTile, shared_from_this() ); 401 } 402 } 403 } 404 delete res; 405 406 if(isCritArrow()) 407 { 408 for (int i = 0; i < 4; i++) 409 { 410 level->addParticle(eParticleType_crit, x + xd * i / 4.0f, y + yd * i / 4.0f, z + zd * i / 4.0f, -xd, -yd + 0.2, -zd); 411 } 412 } 413 414 x += xd; 415 y += yd; 416 z += zd; 417 418 double sd = sqrt(xd * xd + zd * zd); 419 yRot = (float) (atan2(xd, zd) * 180 / PI); 420 xRot = (float) (atan2(yd, sd) * 180 / PI); 421 422 while (xRot - xRotO < -180) 423 xRotO -= 360; 424 while (xRot - xRotO >= 180) 425 xRotO += 360; 426 427 while (yRot - yRotO < -180) 428 yRotO -= 360; 429 while (yRot - yRotO >= 180) 430 yRotO += 360; 431 432 xRot = xRotO + (xRot - xRotO) * 0.2f; 433 yRot = yRotO + (yRot - yRotO) * 0.2f; 434 435 436 float inertia = 0.99f; 437 float gravity = 0.05f; 438 439 if (isInWater()) 440 { 441 for (int i = 0; i < 4; i++) 442 { 443 float s = 1 / 4.0f; 444 level->addParticle(eParticleType_bubble, x - xd * s, y - yd * s, z - zd * s, xd, yd, zd); 445 } 446 inertia = 0.80f; 447 } 448 449 xd *= inertia; 450 yd *= inertia; 451 zd *= inertia; 452 yd -= gravity; 453 454 setPos(x, y, z); 455 456 checkInsideTiles(); 457} 458 459void Arrow::addAdditonalSaveData(CompoundTag *tag) 460{ 461 tag->putShort(L"xTile", (short) xTile); 462 tag->putShort(L"yTile", (short) yTile); 463 tag->putShort(L"zTile", (short) zTile); 464 tag->putByte(L"inTile", (byte) lastTile); 465 tag->putByte(L"inData", (byte) lastData); 466 tag->putByte(L"shake", (byte) shakeTime); 467 tag->putByte(L"inGround", (byte) (inGround ? 1 : 0)); 468 tag->putByte(L"pickup", (byte) pickup); 469 tag->putDouble(L"damage", baseDamage); 470} 471 472void Arrow::readAdditionalSaveData(CompoundTag *tag) 473{ 474 xTile = tag->getShort(L"xTile"); 475 yTile = tag->getShort(L"yTile"); 476 zTile = tag->getShort(L"zTile"); 477 lastTile = tag->getByte(L"inTile") & 0xff; 478 lastData = tag->getByte(L"inData") & 0xff; 479 shakeTime = tag->getByte(L"shake") & 0xff; 480 inGround = tag->getByte(L"inGround") == 1; 481 if (tag->contains(L"damage")) 482 { 483 baseDamage = tag->getDouble(L"damage"); 484 } 485 486 if (tag->contains(L"pickup")) 487 { 488 pickup = tag->getByte(L"pickup"); 489 } 490 else if (tag->contains(L"player")) 491 { 492 pickup = tag->getBoolean(L"player") ? PICKUP_ALLOWED : PICKUP_DISALLOWED; 493 } 494} 495 496void Arrow::playerTouch(shared_ptr<Player> player) 497{ 498 if (level->isClientSide || !inGround || shakeTime > 0) return; 499 500 bool bRemove = pickup == PICKUP_ALLOWED || (pickup == PICKUP_CREATIVE_ONLY && player->abilities.instabuild); 501 502 if (pickup == PICKUP_ALLOWED) 503 { 504 if (!player->inventory->add( shared_ptr<ItemInstance>( new ItemInstance(Item::arrow, 1) ) )) 505 { 506 bRemove = false; 507 } 508 } 509 510 if (bRemove) 511 { 512 playSound(eSoundType_RANDOM_POP, 0.2f, ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f); 513 player->take(shared_from_this(), 1); 514 remove(); 515 } 516} 517 518bool Arrow::makeStepSound() 519{ 520 return false; 521} 522 523float Arrow::getShadowHeightOffs() 524{ 525 return 0; 526} 527 528void Arrow::setBaseDamage(double baseDamage) 529{ 530 this->baseDamage = baseDamage; 531} 532 533double Arrow::getBaseDamage() 534{ 535 return baseDamage; 536} 537 538void Arrow::setKnockback(int knockback) 539{ 540 this->knockback = knockback; 541} 542 543bool Arrow::isAttackable() 544{ 545 return false; 546} 547 548void Arrow::setCritArrow(bool critArrow) 549{ 550 byte flags = entityData->getByte(ID_FLAGS); 551 if (critArrow) 552 { 553 entityData->set(ID_FLAGS, (byte) (flags | FLAG_CRIT)); 554 } 555 else 556 { 557 entityData->set(ID_FLAGS, (byte) (flags & ~FLAG_CRIT)); 558 } 559} 560 561bool Arrow::isCritArrow() 562{ 563 byte flags = entityData->getByte(ID_FLAGS); 564 return (flags & FLAG_CRIT) != 0; 565}