feat: optional property rent

Off unless property_rent_enabled is on. Each property world's rent comes from its PropertyTemplate
row (minimumPrice every rentDuration x durationType; Block Yard is free), unless the new Property
Rent dashboard page sets another price or period (property_rent_manage). Rent is taken from the
owner's coins shortly after their character loads, with a mail receipt; unpaid rent is mailed and,
after property_rent_grace_days, makes the property private until it is paid, like live. The
property management component refuses public or best friends privacy while rent is overdue and a
property world that loads overdue makes itself private. Property game messages are unchanged.

Fixes #943

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-26 23:29:57 -05:00
parent b2403b09ea
commit 680615ba9f
31 changed files with 784 additions and 3 deletions

View File

@@ -48,8 +48,8 @@
</div>
{% endif %}
{% set worldPages = ["world3d", "reports", "contraband"] %}
{% if can.players_view or can.reports_view %}
{% set worldPages = ["world3d", "reports", "contraband", "property_rent"] %}
{% if can.players_view or can.reports_view or can.properties_view %}
<div class="nav-group">
<button class="nav-group-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#nav-world" aria-expanded="{% if current_page in worldPages %}true{% else %}false{% endif %}" aria-controls="nav-world">
World &amp; Economy<span class="nav-group-dot" title="Something in here needs attention"></span>
@@ -59,6 +59,7 @@
{% if can.players_view %}<a href="/world3d" class="list-group-item list-group-item-action{% if current_page == "world3d" %} active{% endif %}">World 3D</a>{% endif %}
{% if can.reports_view %}<a href="/reports" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center{% if current_page == "reports" %} active{% endif %}">Economy &amp; Map <span class="badge rounded-pill text-bg-danger d-none" data-badge="reports" title="Open economy flags"></span></a>{% endif %}
{% if can.reports_view %}<a href="/contraband" class="list-group-item list-group-item-action{% if current_page == "contraband" %} active{% endif %}">Contraband</a>{% endif %}
{% if can.properties_view %}<a href="/property_rent" class="list-group-item list-group-item-action{% if current_page == "property_rent" %} active{% endif %}">Property Rent</a>{% endif %}
</div>
</div>
</div>

View File

@@ -0,0 +1,25 @@
{% extends "base.jinja2" %}
{% block title %}Property Rent - DarkflameServer{% endblock %}
{% block content %}
<div id="propertyRentPage">
<div class="mb-3">
<h2 class="mb-1">Property Rent</h2>
<p class="text-body-secondary mb-0">What owners pay for each property world, like live. Rent is taken from the owner's coins when they log in;
if they can't pay, their property is made private after the grace period and stays private until it is paid (nothing on it changes).
Each world starts with its PropertyTemplate rent (Block Yard is free); set a price here to change it, 0 to make it free.</p>
</div>
<div class="alert alert-secondary d-none" id="offNote">Rent is off: turn on <a href="/settings#property_rent_enabled"><code>property_rent_enabled</code></a> in Settings to charge it.</div>
<div class="card">
<table class="table table-sm align-middle mb-0 table-stack">
<thead><tr><th>World</th><th>Template</th><th>Set here</th><th>Charged</th><th></th></tr></thead>
<tbody id="rows"></tbody>
</table>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="/js/property-rent.js"></script>
{% endblock %}