| 505 | } |
| 506 | |
| 507 | void Particles_CustomEffect(int effectID, float x, float y, float z, float originX, float originY, float originZ) { |
| 508 | struct CustomParticle* p; |
| 509 | struct CustomParticleEffect* e = &Particles_CustomEffects[effectID]; |
| 510 | int i, count = e->particleCount; |
| 511 | Vec3 offset, delta, origin; |
| 512 | float d; |
| 513 | |
| 514 | origin.x = originX; origin.y = originY; origin.z = originZ; |
| 515 | |
| 516 | for (i = 0; i < count; i++) |
| 517 | { |
| 518 | if (custom_count == PARTICLES_MAX) Custom_RemoveAt(0); |
| 519 | p = &custom_particles[custom_count++]; |
| 520 | p->effectId = effectID; |
| 521 | |
| 522 | offset.x = Random_Float(&rnd) - 0.5f; |
| 523 | offset.y = Random_Float(&rnd) - 0.5f; |
| 524 | offset.z = Random_Float(&rnd) - 0.5f; |
| 525 | Vec3_Normalise(&offset); |
| 526 | |
| 527 | /* See https://karthikkaranth.me/blog/generating-random-points-in-a-sphere/ */ |
| 528 | /* 'Using normally distributed random numbers' */ |
| 529 | d = Random_Float(&rnd); |
| 530 | d = Math_Exp2(Math_Log2(d) / 3.0); /* d^1/3 for better distribution */ |
| 531 | d *= e->spread; |
| 532 | |
| 533 | p->base.lastPos.x = x + offset.x * d; |
| 534 | p->base.lastPos.y = y + offset.y * d; |
| 535 | p->base.lastPos.z = z + offset.z * d; |
| 536 | |
| 537 | Vec3_Sub(&delta, &p->base.lastPos, &origin); |
| 538 | Vec3_Normalise(&delta); |
| 539 | |
| 540 | p->base.velocity.x = delta.x * e->speed; |
| 541 | p->base.velocity.y = delta.y * e->speed; |
| 542 | p->base.velocity.z = delta.z * e->speed; |
| 543 | |
| 544 | p->base.nextPos = p->base.lastPos; |
| 545 | p->base.lifetime = e->baseLifetime + (e->baseLifetime * e->lifetimeVariation) * ((Random_Float(&rnd) - 0.5f) * 2); |
| 546 | p->totalLifespan = p->base.lifetime; |
| 547 | |
| 548 | p->base.size = e->size + (e->size * e->sizeVariation) * ((Random_Float(&rnd) - 0.5f) * 2); |
| 549 | |
| 550 | /* Don't spawn custom particle inside a block (otherwise it appears */ |
| 551 | /* for a few frames, then disappears in first PhysicsTick call)*/ |
| 552 | collideFlags = e->collideFlags; |
| 553 | if (IntersectsBlock(&p->base, CustomParticle_CanPass)) custom_count--; |
| 554 | } |
| 555 | } |
| 556 | #else |
| 557 | static int custom_count; |
| 558 |
no test coverage detected