Skip to content

Commit

Permalink
Fix Stasis text, simplify readme
Browse files Browse the repository at this point in the history
  • Loading branch information
serprex committed Jan 23, 2024
1 parent 2a088e7 commit 993e119
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 191 deletions.
85 changes: 28 additions & 57 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,84 +1,55 @@
[![Test](https://github.com/serprex/openEtG/workflows/.github/workflows/cargo-test.yml/badge.svg)](https://github.com/serprex/openEtG/actions?query=workflow%3A.github%2Fworkflows%2Fcargo-test.yml)

# openEtG

openEtG is an open source fork of the Flash ccg [Elements](http://elementsthegame.com).
openEtG is an open source fork of the Flash ccg [Elements the Game](http://elementsthegame.com).

## Developer Instructions

### Getting Started
1. Download all dependencies listed below
2. Clone the repository:
```bash
```sh
git clone https://github.com/serprex/openEtG && cd openEtG
3. Install atlas files:
```bash
curl --compressed 'https://etg.dek.im/assets/{atlas.json,atlas.webp,atlas.css}' -o 'assets/#1'
```
3. Generate asset atlas:
```sh
npm run build-atlas
```
4. Copy sample configuration files:
```bash
```sh
cp config-sample.json config.json
cp wsconfig-sample.json wsconfig.json
```
5. Configure `config.json` to connect your instance of postgresql
- Specify the http port you will listen on for web service requests
- This should match your `wsconfig.json` `wsport`
- Specify the user to connect your postgres server
- Ensure that you created the user on your postgres server and provided proper permissions
- `postgres` is default administrative account
- `initdb.sql` script will generate a userrole `Codesmith` by default to enable special in-game commands
- You can verify your specified DB was created with:
```bash
psql -d postgres -c "select * from pg_database;"
- Specify the host of your postgres server
- Specify the port number of your postgres server
- Specify the database name you created on your postgres server
- If certificates are required to access your instance, they can be included under the `certs` key
6. Build
- Compile to WebAssembly using Rust's compiler/package manager
```bash
cargo build --release --manifest-path ../openEtG/src/rs/server/Cargo.toml --target wasm32-unknown-unknown
- Generate JavaScript and TypeScript bindings to the output directories
- This will generate:
1. `_bg.js` in `./pkg` as the translator between JS and WAsm
2. `_bg.wasm` in `./pkg` as a background support for the WAsm
3. The primary `.wasm` file in the `./release` folder
```bash
wasm-bindgen --no-typescript --weak-refs --out-dir ./src/rs/pkg ./src/rs/target/wasm32-unknown-unknown/release/etg.wasm
- Tell Webpack to build the Javascript and other assets specified in `webpack.config.js` for a specific distribution mode
```bash
webpack --mode=production
8. Clean up hanging build files to prevent build-caching issues (optional)
```bash
cargo sweep ../openEtG/src/rs/server -i
6.
- `psql -f scripts/initdb.sql` will generate initial schema
7. Build
```sh
npm run build
```
8. Run server
```sh
cargo run --manifest-path=./src/rs/server/Cargo.toml
```
### Testing

1. Add unit tests to `lib.rs` and tag them with `[#test]`. _When generating tests, apply the MVP philosophy to keep lib.rs small_
1. Add unit tests to `lib.rs`
2. To run unit tests:
```bash
cargo test --lib --manifest-path=../openEtG/src/rs/Cargo.toml
3. To run a fully test:
```bash
cargo test --manifest-path==../openEtG/src/rs/Cargo.toml
```sh
cargo test --manifest-path=./src/rs/Cargo.toml
```

## Dependencies

1. git
1. nodejs
1. postgresql
1. rustup
- Install
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
- Update your terminals environment parameters, or reboot
```bash
source "$HOME/.cargo/env"
1. rust's JavaScript type translation which allows JavaScript to call Rust APIs and Rust functions to catch JavaScript exceptions
```bash
cargo install wasm-bindgen-cli

### Optional

1. cargo sweep helps to clean up caching issues between builds
```bash
cargo install cargo-sweep
1. [git](http://git-scm.com)
1. [nodejs](https://nodejs.org)
1. [postgresql](https://www.postgresql.org/)
1. [rustup](https://rustup.rs)
1. [wasm-bindgen-cli](https://rustwasm.github.io/wasm-bindgen/reference/cli.html)
3 changes: 0 additions & 3 deletions src/rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,3 @@ wasm-opt = false
opt-level = "z"
lto = "fat"
codegen-units = 1

[build]
target = "wasm32-unknown-unknown"
247 changes: 116 additions & 131 deletions src/rs/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -879,156 +879,141 @@ impl<'a> SkillThing<'a> {

pub fn info(&self) -> String {
let card = self.card();
if card.kind == Kind::Spell && matches!(self, &Self::Card(..)) {
card.skill
.iter()
.find(|&(k, _)| *k == Event::Cast)
.and_then(|&(_, sk)| sk.first())
.cloned()
.and_then(|sk| self.sktext(Event::Cast, sk))
.map(|s| {
let mut owned = s.into_owned();
owned.push('.');
owned
})
.unwrap_or(String::new())
} else {
let mut ret = String::new();
let mut stext = String::new();
for (k, v) in self.status().iter().cloned() {
if v == 0 {
continue;
}
match k {
Stat::cost => {
let card = self.card();
let costele = self.costele();
if v != card.cost as i16 || costele != card.costele as i16 {
write!(ret, "{v}:{}, ", costele).ok();
}
}
Stat::adrenaline => {
if v != 1 {
write!(ret, "{v} ").ok();
}
ret.push_str("adrenaline, ");
let mut ret = String::new();
let mut stext = String::new();
for (k, v) in self.status().iter().cloned() {
if v == 0 {
continue;
}
match k {
Stat::cost => {
let card = self.card();
let costele = self.costele();
if v != card.cost as i16 || costele != card.costele as i16 {
write!(ret, "{v}:{}, ", costele).ok();
}
Stat::casts => {
write!(ret, "{v} casts, ").ok();
}
Stat::adrenaline => {
if v != 1 {
write!(ret, "{v} ").ok();
}
Stat::charges if v != 1 => {
match *self {
Self::Card(cards, c) => {
if !c.skill.iter().any(|&(ev, sk)| ev == Event::OwnAttack && sk.iter().cloned().any(|s| s == Skill::losecharge)) {
write!(stext, "Enters play with {v} {}.\n", if self.get_flag(Flag::stackable) { "stacks" } else { "charges" }).ok();
}
ret.push_str("adrenaline, ");
}
Stat::casts => {
write!(ret, "{v} casts, ").ok();
}
Stat::charges if v != 1 => {
match *self {
Self::Card(cards, c) => {
if !c.skill.iter().any(|&(ev, sk)| ev == Event::OwnAttack && sk.iter().cloned().any(|s| s == Skill::losecharge)) {
write!(stext, "Enters play with {v} {}.\n", if self.get_flag(Flag::stackable) { "stacks" } else { "charges" }).ok();
}
_ => (),
}
_ => (),
}
Stat::delayed => {
write!(ret, "{v} delay, ").ok();
}
Stat::dive => {
write!(ret, "{v} dive, ").ok();
}
Stat::flooding =>
stext.push_str("Non aquatic creatures past first five (seven on first effective turn) creature slots die on turn end. Consumes 1:7"),
Stat::frozen => {
match *self {
Self::Thing(..) => write!(ret, "{v} frozen, "),
Self::Card(..) => write!(stext, "Enters play frozen for {} turn{}.\n", v, if v == 1 { "" } else { "s" }),
}.ok();
}
Stat::poison => {
match *self {
Self::Thing(..) => write!(ret, "{v} poison, "),
}
Stat::delayed => {
write!(ret, "{v} delay, ").ok();
}
Stat::dive => {
write!(ret, "{v} dive, ").ok();
}
Stat::flooding =>
stext.push_str("Non aquatic creatures past first five (seven on first effective turn) creature slots die on turn end. Consumes 1:7"),
Stat::frozen => {
match *self {
Self::Thing(..) => write!(ret, "{v} frozen, "),
Self::Card(..) => write!(stext, "Enters play frozen for {} turn{}.\n", v, if v == 1 { "" } else { "s" }),
}.ok();
}
Stat::poison => {
match *self {
Self::Thing(..) => write!(ret, "{v} poison, "),
Self::Card(..) => write!(stext, "Enters play with {v} poison.\n"),
}.ok();
}
Stat::lives => {
if v == 1 {
write!(ret, "last life, ").ok();
} else {
write!(ret, "{v} lives, ").ok();
}
}
Stat::steam => {
write!(ret, "{v} steam, ").ok();
}
Stat::storedpower => {
write!(ret, "{v} stored, ").ok();
Stat::lives => {
if v == 1 {
write!(ret, "last life, ").ok();
} else {
write!(ret, "{v} lives, ").ok();
}
_ => ()
}
}
for k in self.flags() {
match k {
Flag::cloak => ret.push_str("Cloaks your field. Opponent cannot see your actions or directly target your other cards.\n"),
Flag::tunnel => ret.push_str("Any of your creatures that are burrowed bypass shields.\n"),
Flag::patience =>
ret.push_str("Each turn delay own creatures. They gain 2|2. 5|5 if flooded. Unique.\n"),
Flag::voodoo =>
ret.push_str("Whenever this creature takes non-lethal damage or is affected by any status, that status or damage is also applied to opponent.\n"),
Flag::nightfall => ret.push_str(if self.upped() {
"Nocturnal creatures gain 2|1 while Eclipse is in play. Does not stack.\n"
} else {
"Nocturnal creatures gain 1|1 while Nightfall is in play. Does not stack.\n"
}),
Flag::whetstone => ret.push_str(if self.upped() {
"Weapons & golems gain 1|2 while Whetstone is in play. Does not stack.\n"
} else {
"Weapons & golems gain 1|1 while Whetstone is in play. Does not stack.\n"
}),
Flag::additive => ret.push_str("additive, "),
Flag::aflatoxin => ret.push_str("aflatoxin, "),
Flag::airborne => ret.push_str("airborne, "),
Flag::appeased => ret.push_str("appeased, "),
Flag::aquatic => ret.push_str("aquatic, "),
Flag::burrowed => ret.push_str("burrowed, "),
Flag::golem => ret.push_str("golem, "),
Flag::immaterial => ret.push_str("immaterial, "),
Flag::momentum => ret.push_str("momentum, "),
Flag::mutant => ret.push_str("mutant, "),
Flag::neuro => ret.push_str("neuro, "),
Flag::nocturnal => ret.push_str("nocturnal, "),
Flag::poisonous => ret.push_str("poisonous, "),
Flag::psionic => ret.push_str("psionic, "),
Flag::ranged => ret.push_str("ranged, "),
Flag::ready => ret.push_str("ready, "),
Flag::reflective => ret.push_str("reflective, "),
Flag::vindicated => ret.push_str("vindicated, "),
_ => ()
Stat::steam => {
write!(ret, "{v} steam, ").ok();
}
Stat::storedpower => {
write!(ret, "{v} stored, ").ok();
}
_ => ()
}
let retlen = ret.len();
if retlen > 2 {
ret.truncate(retlen - 2);
ret.push_str(".\n");
}
for k in self.flags() {
match k {
Flag::cloak => ret.push_str("Cloaks your field. Opponent cannot see your actions or directly target your other cards.\n"),
Flag::tunnel => ret.push_str("Any of your creatures that are burrowed bypass shields.\n"),
Flag::patience =>
ret.push_str("Each turn delay own creatures. They gain 2|2. 5|5 if flooded. Unique.\n"),
Flag::voodoo =>
ret.push_str("Whenever this creature takes non-lethal damage or is affected by any status, that status or damage is also applied to opponent.\n"),
Flag::nightfall => ret.push_str(if self.upped() {
"Nocturnal creatures gain 2|1 while Eclipse is in play. Does not stack.\n"
} else {
"Nocturnal creatures gain 1|1 while Nightfall is in play. Does not stack.\n"
}),
Flag::whetstone => ret.push_str(if self.upped() {
"Weapons & golems gain 1|2 while Whetstone is in play. Does not stack.\n"
} else {
"Weapons & golems gain 1|1 while Whetstone is in play. Does not stack.\n"
}),
Flag::additive => ret.push_str("additive, "),
Flag::aflatoxin => ret.push_str("aflatoxin, "),
Flag::airborne => ret.push_str("airborne, "),
Flag::appeased => ret.push_str("appeased, "),
Flag::aquatic => ret.push_str("aquatic, "),
Flag::burrowed => ret.push_str("burrowed, "),
Flag::golem => ret.push_str("golem, "),
Flag::immaterial => ret.push_str("immaterial, "),
Flag::momentum => ret.push_str("momentum, "),
Flag::mutant => ret.push_str("mutant, "),
Flag::neuro => ret.push_str("neuro, "),
Flag::nocturnal => ret.push_str("nocturnal, "),
Flag::poisonous => ret.push_str("poisonous, "),
Flag::psionic => ret.push_str("psionic, "),
Flag::ranged => ret.push_str("ranged, "),
Flag::ready => ret.push_str("ready, "),
Flag::reflective => ret.push_str("reflective, "),
Flag::vindicated => ret.push_str("vindicated, "),
_ => ()
}
ret.push_str(&stext);
drop(stext);
}
let retlen = ret.len();
if retlen > 2 {
ret.truncate(retlen - 2);
ret.push_str(".\n");
}
ret.push_str(&stext);
drop(stext);

self.skills(|ev, sk| {
if ev != Event::Cast || self.kind() != Kind::Spell || self.card().kind != Kind::Spell {
for &s in sk {
if let Some(text) = self.sktext(ev, s) {
if ev == Event::Cast {
write!(ret, "{}:{} ", self.cast(), self.castele()).ok();
}
ret.push_str(&text);
ret.push_str(".\n");
self.skills(|ev, sk| {
if matches!(self, &Self::Card(..)) || ev != Event::Cast || self.kind() != Kind::Spell || self.card().kind != Kind::Spell {
for &s in sk {
if let Some(text) = self.sktext(ev, s) {
if ev == Event::Cast && !matches!(self, &Self::Card(..)) {
write!(ret, "{}:{} ", self.cast(), self.castele()).ok();
}
ret.push_str(&text);
ret.push_str(".\n");
}
}
});

let retlen = ret.len();
if retlen > 1 {
ret.truncate(retlen - 1);
}
ret
});

let retlen = ret.len();
if retlen > 1 {
ret.truncate(retlen - 1);
}
ret
}
}

Expand Down

0 comments on commit 993e119

Please sign in to comment.