/* * Called by the world that's holding the entity every tick (50ms). * A return value of true will cause the world to destroy the entity. */ bool e_pickup::tick (world &w) { if (!valid) return false; if (entity::tick (w)) return true; if (!pickable ()) return false; // fetch closest player std::pair<player *, double> closest; int i = 0; e_pickup *me = this; w.get_players ().all ( [&i, me, &closest] (player *pl) { if (pl->is_dead ()) return; double dist = calc_distance_squared (me->pos, pl->pos); if (i == 0) closest = {pl, dist}; else { if (dist < closest.second) closest = {pl, dist}; } ++ i; }); if ((i == 0) || (closest.second > 2.25)) return false; player *pl = closest.first; if (!pl) return false; int r = pl->inv.add (this->data); if (r == 0) { w.get_players ().send_to_all_visible ( packets::play::make_collect_item (this->eid, pl->get_eid ()), this); } this->data.set_amount (r); pl->send (packets::play::make_sound_effect ("random.pop", this->pos.x, this->pos.y, this->pos.z, 0.2f, 98)); if (this->data.empty ()) { this->valid = false; w.despawn_entity (this); return true; } return false; }
void shark::tick (world &w, int x, int y, int z, int data, void *ptr, std::minstd_rand& rnd) { if (y <= 0) { w.queue_update (x, y, z, BT_AIR); return; } if (w.get_final_block (x, y, z).id != BT_SHARK) return; int below = w.get_final_block (x, y - 1, z).id; if (below == BT_AIR || (_is_water (below) && (w.get_final_block (x, y + 1, z).id == BT_AIR))) { w.queue_update (x, y, z, _sur_water (w, x, y, z)); w.queue_update (x, y - 1, z, BT_SHARK); } else { int nx = x, ny = y, nz = z; // find closest player player *target = nullptr; w.get_players ().all ( [x, y, z, &target] (player *pl) { double dx = x - pl->pos.x; double dy = y - pl->pos.y; double dz = z - pl->pos.z; double dm = dx*dx + dy*dy + dz*dz; if (dm > 6*6) return; if (!target) target = pl; else { double pdx = x - target->pos.x; double pdy = y - target->pos.y; double pdz = z - target->pos.z; if (dm < (pdx*pdx + pdy*pdy + pdz*pdz)) target = pl; } }); if (!target) { // move around in a random fashion std::uniform_int_distribution<> dis (0, 5); switch (dis (rnd)) { case 0: -- ny; break; case 1: ++ ny; break; case 2: -- nz; break; case 3: ++ nz; break; case 4: -- nx; break; case 5: ++ nx; break; } } else { if (x < target->pos.x) { if (_is_water (w.get_final_block (x + 1, ny, nz).id)) ++ nx; } else if (x > target->pos.x) { if (_is_water (w.get_final_block (x - 1, ny, nz).id)) -- nx; } if (y < target->pos.y) { if (_is_water (w.get_final_block (nx, y + 1, nz).id)) ++ ny; } else if (y > target->pos.y) { if (_is_water (w.get_final_block (nx, y - 1, nz).id)) -- ny; } if (z < target->pos.z) { if (_is_water (w.get_final_block (nx, ny, z + 1).id)) ++ nz; } else if (z > target->pos.z) { if (_is_water (w.get_final_block (nx, ny, z - 1).id)) -- nz; } } int prev = _try_block (w, nx, ny, nz); if (prev == -1) w.queue_physics (x, y, z, 0, nullptr, this->tick_rate ()); else w.queue_update (x, y, z, prev, 0, 0, 0, nullptr, nullptr, false); } }