Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions Modules/Alien/data/rulesets.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

return [
/*
[
'description' => '',
'id' => '',
'isbn' => '',
'name' => '',
'required' => false,
],
*/
[
'description' => 'The job was routine, the money fair. Then the damn company diverted you to answer a distress call from a ship that disappeared almost 80 years ago—a derelict carrying something bizarre, twisted, and alien. What the ship’s frozen crew brought back with them was bad enough—what they themselves were turning into was a bloody nightmare. Add to that an annoying sensor ghost shadowing you in the void, and your stress level is shot.||It’s all a bit much.||You don’t get paid enough to deal with monsters. But hold your breath, count to three, and play your cards right with this one, and you just might walk away very rich. Oh, who am I kidding?||You’re all going to die.||Chariot of the Gods is a complete Cinematic Scenario for the ALIEN Roleplaying Game written by sci-fi novelist Andrew E.C. Gaska. The 48-page booklet designed to introduce you to the game while at the same time taking you on a thrilling, terror-filled ride into deep space where no one can hear you scream. Chariot of the Gods is designed for 3–5 players plus the GM and takes at least 4–5 hours to complete.',
'id' => 'alien-chariot-of-the-gods',
'isbn' => '978-91-88805-91-1',
'name' => 'Chariot of the Gods',
'required' => false,
],
[
'description' => 'Space is vast, dark, and not your friend. Gamma rays and neutrino bursts erupt from dying stars to cook you alive, black holes tear you apart, and the void itself boils your blood and seizes your brain. Try to scream and no one can hear you—hold your breath and you rupture your lungs. Space isn’t as empty as you’d think, either—its frontiers are ever expanding. Rival governments wage a cold war of aggression while greedy corporations vie for valuable resources. Colonists reach for the stars and gamble with their lives—each new world tamed is either feast or famine. And there are things lurking in the shadows of every asteroid—things strange and different and deadly.||Things alien.||This is the official ALIEN tabletop roleplaying game—a universe of body horror and corporate brinkmanship, where synthetic people play god while space truckers and marines serve host to newborn ghoulish creatures. It’s a harsh and unforgiving universe and you are nothing if not expendable.||Stay alive if you can.||The ALIEN tabletop roleplaying game is a beautifully illustrated full-color book of 392 pages, both presenting the world of ALIEN in the year 2183 and a fast and effective ruleset designed specifically to enhance the ALIEN experience. The game supports two distinct game modes:||* Cinematic play is based on pre-made scenarios that emulate the dramatic arc of an ALIEN film. Designed to be played in a single session, this game mode emphasizes high stakes and fast and brutal play. You are not all expected to survive. The core rulebook contains one introductory Cinematic scenario, Hope’s Last Day.||* Campaign play is designed for longer continuous play with the same cast of player characters over many game sessions, letting you explore the ALIEN universe freely, sandbox style. The core rulebook contains random tables and other powerful tools to quickly create star systems, colonies, missions, encounters, and NPCs for your campaign.||The rules of the game are based on the acclaimed Year Zero Engine, used in award-winning games such as Tales from the Loop and Mutant: Year Zero, but adapted and further developed to fully support and enhance the core themes of ALIEN: horror and action in the cold darkness of space.',
'id' => 'alien-core',
'isbn' => '978-91-88805-55-3',
'name' => 'Core Rulebook',
'required' => true,
],
];
22 changes: 22 additions & 0 deletions Modules/Avatar/data/rulesets.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

return [
/*
[
'description' => '',
'id' => '',
'isbn' => '',
'name' => '',
'required' => false,
],
*/
[
'description' => '',
'id' => 'avatar-core',
'isbn' => '',
'name' => 'Core Rulebook',
'required' => true,
],
];
22 changes: 22 additions & 0 deletions Modules/Shadowrun5e/data/rulesets.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

return [
/*
[
'description' => '',
'id' => '',
'isbn' => '',
'name' => '',
'required' => false,
],
*/
[
'description' => 'EVERYTHING HAS A PRICE||There are cracks in the world. They’re slender, dark, and often cold, but they are the only things that keep you hidden. Keep you alive. They are the shadows of the world, and they are where you live.||You are a shadowrunner, thriving in the margins, doing the jobs no one else can. You have no office, no permanent home, no background to check. You are whatever you make yourself. Will you seek justice? Sow seeds of chaos? Sell out to the highest bidder? It’s up to you, but this much is certain: If you do nothing, the streets will eat you alive.||You can survive, even flourish, as long as you do what it takes. Sacrifice part of your soul for bleeding-edge gear. Push the limits of your will learning new and dangerous magic. Wire yourself into the Matrix, making your mind one with screaming streams of data. It’ll cost you something—everything does—but you can make it worth the price.||Shadowrun, Fifth Edition is the newest version of one of the most popular and successful role-playing worlds of all time, a fusion of man, magic, and machine in a dystopian near-future. With rules for character creation, magic, combat, Matrix hacking, rigging, and more, you have everything you need to face the challenges of the Sixth World.',
'id' => 'shadowrun5e-core',
'isbn' => '',
'name' => 'Core Rulebook',
'required' => true,
],
];
94 changes: 94 additions & 0 deletions app/Models/Ruleset.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

declare(strict_types=1);

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Nwidart\Modules\Facades\Module;
use Override;
use Stringable;
use Sushi\Sushi;

use function config;
use function file_exists;
use function sprintf;

/**
* @method static self module(string $module_id)
* @method static self required()
* @phpstan-type RulesetArray array{
* description: string,
* id: string,
* isbn: string,
* name: string,
* required: bool
* }
* @property-read string $name
*/
class Ruleset extends Model implements Stringable
{
use Sushi;

public $incrementing = false;
protected $keyType = 'string';

/**
* @var list<string>
*/
protected $fillable = [
'description',
'id',
'isbn',
'name',
'required',
];

#[Override]
public function __toString(): string
{
return $this->name;
}

#[Override]
public function casts(): array
{
return [
'required' => 'bool',
];
}

/**
* @return array<int, RulesetArray>
*/
public function getRows(): array
{
$rulesets = new Collection();
foreach (Module::allEnabled() as $module) {
$filename = config(sprintf('%s.data_path', $module->getLowerName()))
. 'rulesets.php';
if (file_exists($filename)) {
/** @var array<int, RulesetArray> $ruleset */
$ruleset = require $filename;
$rulesets = $rulesets->concat($ruleset);
}
}

return $rulesets->toArray();
}

#[Scope]
protected function module(Builder $query, string $module): void
{
$query->where('id', 'like', $module . '%');
}

#[Scope]
protected function required(Builder $query): void
{
$query->where('required', '=', true);
}
}
41 changes: 41 additions & 0 deletions tests/Feature/Models/RulesetTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace Tests\Feature\Models;

use App\Models\Ruleset;
use PHPUnit\Framework\Attributes\Medium;
use Tests\TestCase;

#[Medium]
final class RulesetTest extends TestCase
{
public function testScopeModule(): void
{
$rulesets = Ruleset::module('avatar')->get();
self::assertCount(1, $rulesets);
$rulesets = Ruleset::module('alien')->get();
self::assertCount(2, $rulesets);
}

public function testScopeModuleNotFound(): void
{
$rulesets = Ruleset::module('unknown')->get();
self::assertCount(0, $rulesets);
}

public function testScopeRequired(): void
{
$rulesets = Ruleset::module('alien')
->required()
->get();
self::assertCount(1, $rulesets);
}

public function testToString(): void
{
$ruleset = Ruleset::findOrFail('alien-core');
self::assertSame('Core Rulebook', (string)$ruleset);
}
}
Loading