301 lines
6.1 KiB
Markdown
301 lines
6.1 KiB
Markdown
# Ashen Realms – Playable Slice 0.8
|
||
|
||
## Graufurt Merchant & Trade-In Loop
|
||
|
||
**Status:** Implementation Specification
|
||
**Depends on:** Slice 0.7.5
|
||
**Purpose:** Close the first new progression loop by allowing monster trade goods to be exchanged for Silver, regional reputation and World Renown.
|
||
|
||
---
|
||
|
||
## 1. Goal
|
||
|
||
For the first time, the player can turn hunting success into long-term progression.
|
||
|
||
The loop becomes:
|
||
|
||
**Hunt → carry trade goods → return to Graufurt → exchange goods → receive Silver + reputation + World Renown → prepare for the next trip.**
|
||
|
||
Normal monster kills continue to give no direct money or reputation.
|
||
|
||
---
|
||
|
||
## 2. Merchant
|
||
|
||
Introduce one functional merchant in Graufurt.
|
||
|
||
Working name:
|
||
|
||
**Borin, Quartermaster**
|
||
|
||
If an existing project NPC already fills this role, reuse that NPC instead of creating a duplicate.
|
||
|
||
The merchant requires:
|
||
|
||
- local-view/NPC interaction entry point
|
||
- dialogue/open-shop action
|
||
- trade-good exchange view
|
||
- basic shop view
|
||
|
||
The UI must use English player-facing content.
|
||
|
||
---
|
||
|
||
## 3. Merchant Roles
|
||
|
||
Borin initially supports two separate operations:
|
||
|
||
### Trade In
|
||
|
||
The player hands over monster trade goods.
|
||
|
||
The server grants configured rewards.
|
||
|
||
### Shop
|
||
|
||
The player can spend Silver on basic supplies/items already allowed by the current content scope.
|
||
|
||
Reputation gating is introduced in Slice 0.8.5, not here.
|
||
|
||
---
|
||
|
||
## 4. Trade-In Reward Model
|
||
|
||
Each accepted trade good has a data-driven exchange definition.
|
||
|
||
Recommended conceptual fields:
|
||
|
||
```text
|
||
tradeGoodKey
|
||
merchantKey / regionKey
|
||
silverPerUnit
|
||
regionalReputationPerUnit
|
||
worldRenownPerUnit or batch rule
|
||
enabled
|
||
```
|
||
|
||
Exact values are balancing data and may remain provisional.
|
||
|
||
The important architectural rule is:
|
||
|
||
> The kill produces the object. The merchant converts the object into economic and reputation progression.
|
||
|
||
---
|
||
|
||
## 5. Initial Exchangeable Goods
|
||
|
||
At minimum:
|
||
|
||
- Ashen Pelt
|
||
- Tough Hide
|
||
- Raider Insignia
|
||
- Charred Raider Insignia
|
||
|
||
The rarer Charred Raider trade good should be worth visibly more than the basic Ashen Pelt.
|
||
|
||
Do not hardcode reward logic in Angular.
|
||
|
||
---
|
||
|
||
## 6. Reputation Effects
|
||
|
||
A successful exchange can improve:
|
||
|
||
- **regional reputation** for the current progression region
|
||
- **World Renown** as the global long-term progression value
|
||
|
||
Use the reputation/renown system introduced before this slice.
|
||
|
||
If the existing reputation implementation also tracks NPC-specific reputation, the exchange may optionally improve Borin's personal reputation, but the slice must not invent a second competing progression model.
|
||
|
||
The exact reward numbers should be configurable.
|
||
|
||
---
|
||
|
||
## 7. Silver
|
||
|
||
Silver is now primarily earned through exchange and quests/services rather than directly from normal monsters.
|
||
|
||
The merchant exchange must be one of the first reliable Silver sources.
|
||
|
||
Silver is persisted server-side and must be granted in the same transaction as the removal of trade goods.
|
||
|
||
---
|
||
|
||
## 8. Transaction Safety
|
||
|
||
A trade-in is atomic.
|
||
|
||
Conceptually:
|
||
|
||
```text
|
||
validate character ownership
|
||
validate quantity
|
||
validate merchant accepts good
|
||
remove goods
|
||
add Silver
|
||
add regional reputation
|
||
add World Renown
|
||
persist exchange record if needed
|
||
commit
|
||
```
|
||
|
||
If any required step fails, no partial exchange is allowed.
|
||
|
||
The same trade goods must never be redeemable twice.
|
||
|
||
---
|
||
|
||
## 9. API
|
||
|
||
Recommended operation:
|
||
|
||
```text
|
||
POST /api/merchants/:merchantKey/trade-in
|
||
```
|
||
|
||
Example request:
|
||
|
||
```json
|
||
{
|
||
"items": [
|
||
{ "itemKey": "ashen-pelt", "quantity": 5 }
|
||
]
|
||
}
|
||
```
|
||
|
||
Example response shape:
|
||
|
||
```json
|
||
{
|
||
"consumed": [
|
||
{ "itemKey": "ashen-pelt", "quantity": 5 }
|
||
],
|
||
"rewards": {
|
||
"silver": 20,
|
||
"regionalReputation": 10,
|
||
"worldRenown": 2
|
||
},
|
||
"balances": {
|
||
"silver": 84,
|
||
"regionalReputation": 26,
|
||
"worldRenown": 4
|
||
}
|
||
}
|
||
```
|
||
|
||
Numbers above are illustrative only.
|
||
|
||
---
|
||
|
||
## 10. Trade-In UI
|
||
|
||
The trade-in view should show:
|
||
|
||
- trade good icon
|
||
- name
|
||
- quantity carried
|
||
- exchange value
|
||
- selected quantity
|
||
- resulting reward preview
|
||
- confirmation button
|
||
|
||
Useful actions:
|
||
|
||
- Trade Selected
|
||
- Trade All
|
||
|
||
After completion, show a clear summary:
|
||
|
||
```text
|
||
Trade Complete
|
||
5 Ashen Pelts handed in
|
||
+20 Silver
|
||
+10 Ashen Fields Reputation
|
||
+2 World Renown
|
||
```
|
||
|
||
Do not use a mobile-game reward explosion. Keep presentation consistent with the dark browser-RPG UI.
|
||
|
||
---
|
||
|
||
## 11. Bag Interaction
|
||
|
||
Trade-in removes items from the player's carrying total immediately.
|
||
|
||
Example:
|
||
|
||
```text
|
||
Hides before exchange: 5 / 5
|
||
Trade 5 Ashen Pelts
|
||
Hides after exchange: 0 / 5
|
||
```
|
||
|
||
This immediately frees bag capacity for another trip.
|
||
|
||
---
|
||
|
||
## 12. Basic Shop
|
||
|
||
The shop may initially sell only already-supported basics, such as:
|
||
|
||
- Small Healing Potion
|
||
- simple starter equipment if desired
|
||
|
||
Avoid adding many new items just to populate the shop.
|
||
|
||
The important feature of this slice is **trade-in**, not shop breadth.
|
||
|
||
---
|
||
|
||
## 13. Tests
|
||
|
||
### Exchange
|
||
|
||
- owned goods can be exchanged
|
||
- excessive quantity is rejected
|
||
- unsupported item is rejected
|
||
- trade removes exact quantity
|
||
- Silver is granted
|
||
- regional reputation is granted
|
||
- World Renown follows configured reward rule
|
||
- capacity becomes available after goods are removed
|
||
|
||
### Atomicity
|
||
|
||
- reward failure does not consume goods
|
||
- duplicate request cannot duplicate rewards if request/idempotency protection exists in current architecture
|
||
|
||
### Regression
|
||
|
||
- normal monster victory still grants no Silver/reputation directly
|
||
|
||
---
|
||
|
||
## 14. Acceptance Criteria
|
||
|
||
- [ ] Graufurt has an interactable merchant entry point.
|
||
- [ ] Player can view carried trade goods accepted by the merchant.
|
||
- [ ] Player can exchange selected quantities.
|
||
- [ ] Trade goods are removed server-side.
|
||
- [ ] Silver is granted server-side.
|
||
- [ ] Regional reputation is granted according to configured values.
|
||
- [ ] World Renown is granted according to configured values/rules.
|
||
- [ ] Bag capacity is freed by trade-in.
|
||
- [ ] Exchange is transactional and cannot be duplicated by client manipulation.
|
||
- [ ] The complete Hunt → Return → Trade loop works without DB editing.
|
||
|
||
---
|
||
|
||
## 15. Out of Scope
|
||
|
||
Do not add yet:
|
||
|
||
- reputation-locked shop items
|
||
- referral-based merchant exceptions
|
||
- first tutorial quest
|
||
- advanced buy/sell economy
|
||
- player-to-player trading
|
||
- auction house
|
||
- crafting materials market
|