Skip to content

Commit

Permalink
Merge pull request #218 from HarmlessKey/feature/playerless_campaigns
Browse files Browse the repository at this point in the history
Add players from run campaign
  • Loading branch information
HarmlessHarm authored Apr 20, 2024
2 parents faefaeb + aada2f2 commit abff7d0
Show file tree
Hide file tree
Showing 9 changed files with 419 additions and 230 deletions.
189 changes: 189 additions & 0 deletions src/components/campaign/AddPlayers.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
<template>
<div>
<!-- PLAYERS -->
<hk-card no-margin :min-width="320">
<div slot="header" class="card-header">
Players
<a @click="players_dialog = true" class="btn btn-sm">
<i aria-hidden="true" class="fas fa-plus green mr-1" /> Add players
</a>
</div>
<div class="card-body">
<ul class="entities hasImg" v-if="campaign_players.length">
<li v-for="player in campaign_players" :key="player.key">
<span
class="img"
:style="{
backgroundImage: player_avatar(player)
? 'url(\'' + player_avatar(player) + '\')'
: '',
}"
>
<i aria-hidden="true" v-if="!player_avatar(player)" class="hki-player" />
</span>

<div :class="{ red: inOtherCampaign(player.campaign_id) }">
{{ player.character_name }}
<span
v-if="inOtherCampaign(player.campaign_id)"
class="d-none d-md-inline ml-1 neutral-2"
>
<small>Different Campaign</small>
</span>
</div>

<div class="actions items-center pr-0">
<a class="btn btn-sm bg-neutral-5" @click="removePlayer(player)">
<i aria-hidden="true" class="fas fa-trash-alt"></i>
<q-tooltip anchor="top middle" self="center right">
Remove from campaign
</q-tooltip>
</a>
</div>
</li>
</ul>
<div v-else>
<p>There are no players in this campaign yet.</p>
<a @click="players_dialog = true" class="btn btn-block">Add players</a>
</div>
</div>
<div slot="footer" class="card-footer">
<q-btn label="Close" no-caps v-close-popup />
</div>
</hk-card>

<q-dialog v-model="players_dialog">
<hk-card header="All Players" :min-width="300">
<div slot="header" class="card-header">
Add players
<q-btn icon="close" no-caps flat dense v-close-popup />
</div>

<div class="card-body">
<ul class="entities hasImg">
<li v-for="player in players" :key="player.key">
<span
class="img"
:style="{
backgroundImage: player_avatar(player)
? 'url(\'' + player_avatar(player) + '\')'
: '',
}"
>
<i aria-hidden="true" v-if="!player_avatar(player)" class="hki-player" />
</span>

{{ player.character_name }}

<span v-if="inOtherCampaign(player.campaign_id)">
<span class="d-none d-md-inline ml-1 neutral-3 pr-2"
><small>Different Campaign</small></span
>
</span>

<span v-else-if="checkPlayer(player.campaign_id)">
<i aria-hidden="true" class="fas fa-check pr-2 neutral-2"></i>
</span>

<div v-else class="actions items-center pr-0">
<a @click="addPlayer(player.key)" class="btn btn-sm bg-neutral-5">
<i aria-hidden="true" class="fas fa-plus green"></i>
<q-tooltip anchor="top middle" self="center middle"> Add character </q-tooltip>
</a>
</div>
</li>
</ul>
</div>
</hk-card>
</q-dialog>
</div>
</template>

<script>
import { mapGetters, mapActions } from "vuex";
export default {
name: "AddPlayers",
props: {
campaign: {
type: Object,
required: true,
},
},
data() {
return {
user: this.$store.getters.user,
image: false,
players_dialog: false,
};
},
computed: {
...mapGetters("players", ["players"]),
campaign_players() {
return this.players.filter((player) => {
return player.campaign_id === this.campaign.key;
});
},
},
async mounted() {
await this.get_players();
// Check if the campaign_player count matches the player_count of the campaign
// update if it doesn't match
if (this.campaign_players.length !== this.campaign.player_count) {
this.update_player_count({ id: this.campaign.key, new_count: this.campaign_players.length });
}
},
methods: {
...mapActions("campaigns", [
"campaigns",
"get_campaign",
"add_player",
"delete_player",
"update_player_count",
]),
...mapActions("players", ["get_players"]),
player_avatar(player) {
return player.storage_avatar || player.avatar;
},
addPlayer(id) {
// Set the current HP
this.add_player({
playerId: id,
campaign: this.campaign,
});
},
async removePlayer(player) {
await this.delete_player({
id: this.campaign.key,
player,
});
},
checkPlayer(campaign_id) {
return campaign_id === this.campaign.key;
},
inOtherCampaign(campaign_id) {
return campaign_id && campaign_id !== this.campaign.key;
},
},
};
</script>

<style lang="scss" scoped>
.background {
display: grid;
grid-template-columns: 56px 1fr;
grid-column-gap: 10px;
font-size: 35px;
text-align: center;
.img {
border: solid 1px $neutral-3;
display: block;
width: 56px;
height: 56px;
background-size: cover;
background-position: center top;
}
}
</style>
42 changes: 23 additions & 19 deletions src/components/campaign/Players.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
</div>
<div class="d-flex justify-content-end">
<template v-if="viewerIsUser && page !== 'user'">
<button class="btn btn-sm bg-neutral-5 mr-1" @click="$emit('add-player', true)">
<i aria-hidden="true" class="fas fa-user-plus"></i>
<q-tooltip anchor="top middle" self="center middle">Manage Players</q-tooltip>
</button>
<button
v-if="tier.name !== 'Free' && Object.keys(sync_characters).length && Object.values(players).some(item => item.sync_character)"
class="btn btn-sm bg-neutral-5 mr-1"
Expand All @@ -50,10 +54,7 @@
<i aria-hidden="true" class="fas fa-swords" />
<q-tooltip anchor="top middle" self="center middle">Damage Meters</q-tooltip>
</button>
<button
class="btn btn-sm mr-1 bg-neutral-5"
@click="rest_dialog = true"
>
<button class="btn btn-sm mr-1 bg-neutral-5" @click="rest_dialog = true">
<i aria-hidden="true" class="fas fa-campfire" />
<q-tooltip anchor="top middle" self="center middle">Party rest</q-tooltip>
</button>
Expand Down Expand Up @@ -425,9 +426,7 @@
<div class="card-body">
<p>Reset health and modifiers for every party member.</p>
<p>
<strong>
What should be reset during this rest?
</strong>
<strong> What should be reset during this rest? </strong>
</p>
<q-checkbox
:dark="$store.getters.theme === 'dark'"
Expand All @@ -437,8 +436,8 @@
label="Select all"
@input="checkAll"
/>
<hr class="my-1">
<div v-for="({ label, property }) in resets" :key="property">
<hr class="my-1" />
<div v-for="{ label, property } in resets" :key="property">
<q-checkbox
:dark="$store.getters.theme === 'dark'"
v-model="selected_resets"
Expand Down Expand Up @@ -539,6 +538,7 @@ export default {
};
},
computed: {
...mapGetters(["overencumbered"]),
...mapGetters(["userSettings", "tier"]),
viewerIsUser() {
//If the viewer is the user that runs the campaign
Expand All @@ -550,18 +550,20 @@ export default {
},
selected_resets: {
get() {
return this.selected_setter ? this.selected_setter : this.resets.map((item) => item.property);
return this.selected_setter
? this.selected_setter
: this.resets.map((item) => item.property);
},
set(newVal) {
this.selected_setter = newVal;
}
},
},
all() {
if(this.selected_resets.length === this.resets.length) {
if (this.selected_resets.length === this.resets.length) {
return true;
} else if (this.selected_resets.length) {
return false;
}
}
return null;
},
templateColumns() {
Expand Down Expand Up @@ -663,14 +665,14 @@ export default {
return parseInt(maxHpMod ? maxHp + maxHpMod : maxHp);
},
checkAll(value) {
this.selected_resets = (value) ? this.resets.map((item) => item.property) : [];
this.selected_resets = value ? this.resets.map((item) => item.property) : [];
},
reset() {
for (const [id, player] of Object.entries(this.players)) {
if (!player.dead) {
for (const { property, value } of [...this.resets, { property: "stable" } ]) {
for (const { property, value } of [...this.resets, { property: "stable" }]) {
if (this.selected_resets?.includes(property)) {
this.resetValue(property, value, id, player)
this.resetValue(property, value, id, player);
}
}
}
Expand Down Expand Up @@ -722,9 +724,11 @@ export default {
},
resetValue(property, value, id, player) {
const campaign_player = this.campaign?.players?.[id];
const maxHp = (!this.selected_resets.includes("maxHpMod")) ? this.maxHp(player.maxHp, campaign_player?.maxHpMod) : player.maxHp;
const maxHp = !this.selected_resets.includes("maxHpMod")
? this.maxHp(player.maxHp, campaign_player?.maxHpMod)
: player.maxHp;
const reset_value = property === "curHp" ? maxHp : value;
this.update_campaign_entity({
uid: this.userId,
campaignId: this.campaignId,
Expand All @@ -738,7 +742,7 @@ export default {
if (campaign_player.curHp > maxHp && property !== "curHp") {
this.resetValue("curHp", value, id, player);
}
}
},
},
};
</script>
Expand Down
2 changes: 1 addition & 1 deletion src/services/campaigns.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export class campaignServices {
* Adds an item to the inventory of a campaign
*
* @param {String} uid User ID
* @param {String} campaignId Campaing ID
* @param {String} campaignId Campaign ID
* @param {String} encounterId Encounter ID
* @param {object} item
*/
Expand Down
2 changes: 1 addition & 1 deletion src/services/encounters.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export class encounterServices {
* @param {String} campaignId ID of campaign
* @param {String} encounterId ID of encounter to edit
* @param {string} path Path to parent the property that must be updated (Only needed of the value is nested)
* @param {object} value Object with { proptery: value }
* @param {object} value Object with { property: value }
* @param {boolean} update_search Wether or not search_campaigns must be updated
*/
async updateEncounter(uid, campaignId, encounterId, path, value, update_search = false) {
Expand Down
Loading

0 comments on commit abff7d0

Please sign in to comment.