added shadowrun database
This commit is contained in:
parent
71f771b428
commit
69f7f625f8
88
.vscode/settings.json
vendored
88
.vscode/settings.json
vendored
@ -1,92 +1,6 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"any": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"hash_map": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"charconv": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"csignal": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"list": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"source_location": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"format": "cpp",
|
||||
"fstream": "cpp",
|
||||
"future": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"ranges": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"span": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stdfloat": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"text_encoding": "cpp",
|
||||
"thread": "cpp",
|
||||
"cfenv": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"valarray": "cpp",
|
||||
"variant": "cpp",
|
||||
"*.ipp": "cpp",
|
||||
"expected": "cpp",
|
||||
"queue": "cpp",
|
||||
"stack": "cpp",
|
||||
"strstream": "cpp",
|
||||
"complex": "cpp",
|
||||
"typeindex": "cpp"
|
||||
"thread": "cpp"
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(CrowHTMX)
|
||||
|
||||
set(TARGET_NAME lf-server-admin-panel )
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
@ -30,9 +32,12 @@ foreach(file IN LISTS TEMPLATE_FILES)
|
||||
endforeach()
|
||||
|
||||
# Use Crow from system include (installed via yay -S crow + asio)
|
||||
include_directories(/usr/include)
|
||||
include_directories(/usr/include src src/htmx src/shadowrun src/database)
|
||||
|
||||
add_executable(lf-server-admin-panel src/main.cpp
|
||||
add_executable(${TARGET_NAME}
|
||||
src/main.cpp
|
||||
src/utils.hpp
|
||||
src/utils.cpp
|
||||
src/htmx/HtmxTable.cpp
|
||||
src/htmx/HtmxTable.h
|
||||
src/systemd.cpp
|
||||
@ -46,9 +51,29 @@ add_executable(lf-server-admin-panel src/main.cpp
|
||||
src/htmx_helper.h
|
||||
src/json_settings.cpp
|
||||
src/json_settings.h
|
||||
src/json.hpp)
|
||||
src/json.hpp
|
||||
|
||||
target_link_libraries(lf-server-admin-panel pthread)
|
||||
src/database/database.cpp
|
||||
src/database/database.hpp
|
||||
|
||||
# Shadowrun
|
||||
src/shadowrun/HtmxShItemList.cpp
|
||||
src/shadowrun/HtmxShItemList.hpp
|
||||
src/shadowrun/HtmxShAttributeList.cpp
|
||||
src/shadowrun/HtmxShAttributeList.hpp
|
||||
src/shadowrun/HtmxShCondition.cpp
|
||||
src/shadowrun/HtmxShCondition.hpp
|
||||
src/shadowrun/ShadowrunCharacterForm.hpp
|
||||
src/shadowrun/ShadowrunCharacterForm.cpp
|
||||
src/shadowrun/ShadowrunApi.cpp
|
||||
src/shadowrun/ShadowrunApi.hpp
|
||||
|
||||
|
||||
)
|
||||
|
||||
target_compile_definitions(${TARGET_NAME} PRIVATE APPLICATION_NAME="${TARGET_NAME}")
|
||||
|
||||
target_link_libraries(${TARGET_NAME} pthread sqlite3)
|
||||
|
||||
# Optional: Print build type at configuration time
|
||||
message(STATUS "Configuring build type: ${CMAKE_BUILD_TYPE}")
|
||||
@ -1,6 +1,6 @@
|
||||
## Setup
|
||||
|
||||
pacman -S crow asio gdb gcc cmake make
|
||||
pacman -S crow asio gdb gcc cmake make sqlite3
|
||||
|
||||
## Build
|
||||
|
||||
|
||||
35
src/database/database.cpp
Normal file
35
src/database/database.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include "crow.h"
|
||||
#include "database.hpp"
|
||||
|
||||
Database::Database() :
|
||||
m_db(nullptr)
|
||||
{}
|
||||
|
||||
Database::~Database() {
|
||||
sqlite3_close(m_db);
|
||||
}
|
||||
|
||||
bool Database::exec(const char* sqlQuery) {
|
||||
char* errmsg = nullptr;
|
||||
int rc = sqlite3_exec(m_db, sqlQuery, nullptr, nullptr, &errmsg);
|
||||
if (rc != SQLITE_OK) {
|
||||
CROW_LOG_ERROR << "SQL error: " << errmsg;
|
||||
sqlite3_free(errmsg);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::exec(const std::string& sqlQuery)
|
||||
{
|
||||
exec(sqlQuery.c_str());
|
||||
}
|
||||
|
||||
bool Database::open(){
|
||||
int rc = sqlite3_open("example.db", &m_db);
|
||||
if (rc) {
|
||||
CROW_LOG_ERROR << "Can't open database: " << sqlite3_errmsg(m_db);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
21
src/database/database.hpp
Normal file
21
src/database/database.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef __DATABASE_H__
|
||||
#define __DATABASE_H__
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include <string>
|
||||
|
||||
class Database {
|
||||
|
||||
public:
|
||||
Database();
|
||||
~Database();
|
||||
|
||||
bool open();
|
||||
bool exec(const char* sqlQuery);
|
||||
bool exec(const std::string& sqlQuery);
|
||||
|
||||
private:
|
||||
sqlite3* m_db;
|
||||
};
|
||||
|
||||
#endif // __DATABASE_H__
|
||||
@ -5,6 +5,7 @@
|
||||
#include "systemd.h"
|
||||
#include "htmx_helper.h"
|
||||
#include "json_settings.h"
|
||||
#include "utils.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
31
src/main.cpp
31
src/main.cpp
@ -1,6 +1,4 @@
|
||||
#include <crow.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <print>
|
||||
@ -8,16 +6,11 @@
|
||||
#include "json_settings.h"
|
||||
#include "htmx_helper.h"
|
||||
#include "systemd.h"
|
||||
#include "utils.hpp"
|
||||
#include "ShadowrunApi.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
string load_file(const string& path) {
|
||||
ifstream f(path);
|
||||
stringstream buffer;
|
||||
buffer << f.rdbuf();
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
optional<string> get_body_name(const string& body) {
|
||||
const auto pos = body.find('=');
|
||||
if (pos == std::string::npos) return {};
|
||||
@ -34,11 +27,15 @@ int main() {
|
||||
crow::SimpleApp app;
|
||||
|
||||
CROW_ROUTE(app, "/")([] {
|
||||
return crow::response(load_file("templates/index.html"));
|
||||
return crow::response(utils::loadFile("templates/index.html"));
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/static/<string>")([](const std::string& file) {
|
||||
return crow::response(load_file("static/" + file));
|
||||
return crow::response(utils::loadFile("static/" + file));
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/templates/<string>")([](const std::string& file) {
|
||||
return crow::response(utils::loadFile("templates/" + file));
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/status")([] {
|
||||
@ -80,8 +77,20 @@ int main() {
|
||||
} else {
|
||||
CROW_LOG_ERROR << "failed to load settings : " << opt_settings.error();
|
||||
}
|
||||
|
||||
auto opt_isPortOpen = utils::isLocalPortOpen(httpPort);
|
||||
if (opt_isPortOpen.has_value()){
|
||||
if (opt_isPortOpen.value()){
|
||||
CROW_LOG_ERROR << "Local port : " << httpPort << " is already open";
|
||||
}
|
||||
}
|
||||
else {
|
||||
CROW_LOG_ERROR << "failed to check if local port is open : " << opt_isPortOpen.error();
|
||||
}
|
||||
}
|
||||
|
||||
shadowrun::initApi(app);
|
||||
|
||||
app.loglevel(crow::LogLevel::INFO);
|
||||
app.port(httpPort).multithreaded().run();
|
||||
}
|
||||
|
||||
26
src/shadowrun/HtmxShAttributeList.cpp
Normal file
26
src/shadowrun/HtmxShAttributeList.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include <format>
|
||||
#include "HtmxShAttributeList.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
HtmxShAttributeList::HtmxShAttributeList(const std::string& id, const vector<string>& itemList){
|
||||
html += format("<h2>{}</h2>", id);
|
||||
html += "<div class='grid'>";
|
||||
for (auto& item : itemList){
|
||||
string item_id = utils::to_id_format(id + "_" + item);
|
||||
|
||||
html += format("<label>{}:<input type='text' name='{}'></label>", item, item_id);
|
||||
}
|
||||
html += "</div>";
|
||||
}
|
||||
|
||||
HtmxShAttributeList::HtmxShAttributeList(const std::string& id, const std::vector<std::pair<std::string, std::string>>& itemValueList){
|
||||
html += format("<h2>{}</h2>", id);
|
||||
html += "<div class='grid'>";
|
||||
for (auto& item : itemValueList){
|
||||
string item_id = utils::to_id_format(id + "_" + item.first);
|
||||
html += format("<label>{}:<input type='text' name='{}' value='{}'></label>", item, item_id, item.second);
|
||||
}
|
||||
html += "</div>";
|
||||
}
|
||||
18
src/shadowrun/HtmxShAttributeList.hpp
Normal file
18
src/shadowrun/HtmxShAttributeList.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef HTMXSHATTRIBUTELIST_H
|
||||
#define HTMXSHATTRIBUTELIST_H
|
||||
|
||||
#include "HtmxObject.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class HtmxShAttributeList : public HtmxObject {
|
||||
|
||||
public:
|
||||
// create new item list
|
||||
HtmxShAttributeList(const std::string& id, const std::vector<std::string>& itemList);
|
||||
|
||||
// create new item list where each item as a value
|
||||
HtmxShAttributeList(const std::string& id, const std::vector<std::pair<std::string, std::string>>& itemValueList);
|
||||
};
|
||||
|
||||
#endif // HTMXSHATTRIBUTELIST_H
|
||||
28
src/shadowrun/HtmxShCondition.cpp
Normal file
28
src/shadowrun/HtmxShCondition.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "HtmxShCondition.hpp"
|
||||
#include "../utils.hpp"
|
||||
#include <format>
|
||||
|
||||
using namespace std;
|
||||
|
||||
HtmxShCondition::HtmxShCondition(std::string id, size_t nbrOfBoxes)
|
||||
{
|
||||
html += "<div class='section'>";
|
||||
html += format("<h2>{}</h2>", id);
|
||||
html += "<div class='monitor-track'>";
|
||||
|
||||
int con_value = -1;
|
||||
|
||||
for (size_t i = 0; i < nbrOfBoxes; i++)
|
||||
{
|
||||
string item_id = utils::to_id_format(format("{}_{}",id, i));
|
||||
html += format("<label class='monitor-box'><input type='checkbox' name='{}'></label>", item_id);
|
||||
|
||||
if ( ((i + 1) % 3 == 0) && (i != 0) )
|
||||
{
|
||||
html += format("<div class='monitor-number'>{}</div>", con_value);
|
||||
con_value--;
|
||||
}
|
||||
|
||||
}
|
||||
html += "</div></div>";
|
||||
}
|
||||
13
src/shadowrun/HtmxShCondition.hpp
Normal file
13
src/shadowrun/HtmxShCondition.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef __HTMXSHCONDITION_H__
|
||||
#define __HTMXSHCONDITION_H__
|
||||
|
||||
#include <string>
|
||||
#include "HtmxObject.h"
|
||||
|
||||
class HtmxShCondition : public HtmxObject {
|
||||
|
||||
public:
|
||||
HtmxShCondition(std::string id, size_t nbrOfBoxes);
|
||||
};
|
||||
|
||||
#endif // __HTMXSHCONDITION_H__
|
||||
43
src/shadowrun/HtmxShItemList.cpp
Normal file
43
src/shadowrun/HtmxShItemList.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include <format>
|
||||
#include "HtmxShItemList.hpp"
|
||||
#include "../utils.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
HtmxShItemList::HtmxShItemList(const std::string& id, const std::vector<std::string>& columns, size_t size){
|
||||
html += "<div class='section'>";
|
||||
html += format("<h2>{}</h2>", id);
|
||||
html += format("<div class='grid grid-{}'>", columns.size());
|
||||
for (size_t i = 0; i < size; i++){
|
||||
for (auto& col : columns){
|
||||
string item_id = utils::to_id_format(format("{}_{}_{}", id, i, col));
|
||||
html += format("<input type='text' name='{}' placeholder='{}'>", item_id, col);
|
||||
}
|
||||
}
|
||||
|
||||
html += "</div></div>";
|
||||
}
|
||||
|
||||
/*
|
||||
HtmxShItemList::HtmxShItemList(const std::string& id, const std::vector<std::pair<std::string, std::string>>& itemValueList){
|
||||
html += format("<h2>{}</h2>", id);
|
||||
html += "<div class='grid'>";
|
||||
for (auto& item : itemValueList){
|
||||
string item_id = utils::to_id_format(id + "_" + item.first);
|
||||
html += format("<label>{}:<input type='text' name='{}' value='{}'></label>", item, item_id, item.second);
|
||||
}
|
||||
html += "</div>";
|
||||
|
||||
html += "<div class='section'>";
|
||||
html += format("<h2>{}</h2>", id);
|
||||
html += format("<div class='grid grid-{}'>", columns.size());
|
||||
for (size_t i = 0; i < size; i++){
|
||||
for (auto& col : columns){
|
||||
string item_id = utils::to_id_format(format("{}_{}_{}", id, i, col));
|
||||
html += format("<input type='text' name='{}' placeholder='{}' value='{}'>", item_id, col);
|
||||
}
|
||||
}
|
||||
|
||||
html += "</div></div>";
|
||||
}
|
||||
*/
|
||||
18
src/shadowrun/HtmxShItemList.hpp
Normal file
18
src/shadowrun/HtmxShItemList.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef HTMXSHITEMLIST_H
|
||||
#define HTMXSHITEMLIST_H
|
||||
|
||||
#include "HtmxObject.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class HtmxShItemList : public HtmxObject {
|
||||
|
||||
public:
|
||||
// create new item list,
|
||||
HtmxShItemList(const std::string& id, const std::vector<std::string>& columns, size_t size);
|
||||
|
||||
// create new item list where each item as a value
|
||||
HtmxShItemList(const std::string& id, const std::vector<std::pair<std::string, std::string>>& itemValueList);
|
||||
};
|
||||
|
||||
#endif // HTMXSHITEMLIST_H
|
||||
106
src/shadowrun/ShadowrunApi.cpp
Normal file
106
src/shadowrun/ShadowrunApi.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
|
||||
|
||||
#include "ShadowrunApi.hpp"
|
||||
#include "ShadowrunCharacterForm.hpp"
|
||||
#include "database.hpp"
|
||||
|
||||
namespace shadowrun
|
||||
{
|
||||
|
||||
bool initDb() {
|
||||
auto db = Database();
|
||||
|
||||
if (!db.open()){
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a tables
|
||||
const char* create_sql_chars = "CREATE TABLE IF NOT EXISTS shadowrun_characters ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"name TEXT,"
|
||||
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP);";
|
||||
|
||||
if (!db.exec(create_sql_chars)){
|
||||
CROW_LOG_ERROR << "Failed to create shadowrun_characters table";
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* create_sql_data = "CREATE TABLE IF NOT EXISTS shadowrun_data ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"character_id INTEGER NOT NULL,"
|
||||
"name TEXT NOT NULL,"
|
||||
"value TEXT,"
|
||||
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
|
||||
"updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
|
||||
"FOREIGN KEY (character_id) REFERENCES characters(id) ON DELETE CASCADE);";
|
||||
|
||||
if (!db.exec(create_sql_data)){
|
||||
CROW_LOG_ERROR << "Failed to create shadowrun_data table";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void initApi(crow::SimpleApp& app)
|
||||
{
|
||||
CROW_ROUTE(app, "/api/shadowrun/submit-character").methods("POST"_method)(
|
||||
[](const crow::request& req) {
|
||||
auto params = crow::query_string(req.body);
|
||||
|
||||
std::string name = params.get("name") ? params.get("name") : "";
|
||||
std::string metatype = params.get("metatype") ? params.get("metatype") : "";
|
||||
std::string age = params.get("age") ? params.get("age") : "";
|
||||
// ... extract more fields as needed
|
||||
|
||||
// Optionally save to a DB or do logic here
|
||||
|
||||
// Return response HTML
|
||||
std::ostringstream out;
|
||||
out << "<div class='alert alert-success'>"
|
||||
<< "Character " << name << " submitted successfully!"
|
||||
<< "</div>";
|
||||
|
||||
return crow::response{out.str()};
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/api/shadowrun/character-form")
|
||||
([](const crow::request& req) {
|
||||
auto query = crow::query_string(req.url_params);
|
||||
std::string name = query.get("name") ? query.get("name") : "";
|
||||
|
||||
// TODO: Load data from file or DB using `name`
|
||||
std::string metatype = "Troll";
|
||||
int age = 28;
|
||||
|
||||
return crow::response{ShadowrunCharacterForm().htmx()};
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/api/shadowrun/character-list")
|
||||
([] {
|
||||
std::ostringstream html;
|
||||
|
||||
// Simulated character database
|
||||
std::vector<std::string> characters = { "Trogdor", "Alice", "Zigzag" };
|
||||
|
||||
html << "<form hx-get='/api/shadowrun/character-form' hx-target='#form-container' hx-params='*'>"
|
||||
<< "<label>Character Name: "
|
||||
<< "<select name='name'>";
|
||||
|
||||
for (const auto& name : characters) {
|
||||
html << "<option value='" << name << "'>" << name << "</option>";
|
||||
}
|
||||
|
||||
html << "</select></label>"
|
||||
<< "<button type='submit'>Load Character</button>"
|
||||
<< "</form>";
|
||||
|
||||
return crow::response{html.str()};
|
||||
});
|
||||
|
||||
if(initDb()){
|
||||
CROW_LOG_ERROR << "Failed to Init shadowrun database";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
11
src/shadowrun/ShadowrunApi.hpp
Normal file
11
src/shadowrun/ShadowrunApi.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef __SHADOWRUNAPI_H__
|
||||
#define __SHADOWRUNAPI_H__
|
||||
|
||||
#include <crow.h>
|
||||
|
||||
namespace shadowrun {
|
||||
|
||||
void initApi(crow::SimpleApp& app);
|
||||
|
||||
}
|
||||
#endif // __SHADOWRUNAPI_H__
|
||||
122
src/shadowrun/ShadowrunCharacterForm.cpp
Normal file
122
src/shadowrun/ShadowrunCharacterForm.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "HtmxShItemList.hpp"
|
||||
#include "HtmxShAttributeList.hpp"
|
||||
#include "HtmxShCondition.hpp"
|
||||
#include "ShadowrunCharacterForm.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const vector<string> cCharacterInfo = {
|
||||
"Name",
|
||||
"Metatype",
|
||||
"Age",
|
||||
"Sex",
|
||||
"Nuyen",
|
||||
"Lifestyle",
|
||||
"Total Karma",
|
||||
"Current Karma",
|
||||
"Street Cred",
|
||||
"Notoriety",
|
||||
"Public Awareness"
|
||||
};
|
||||
|
||||
static const vector<string> cAttributes = {
|
||||
"Body",
|
||||
"Agility",
|
||||
"Reaction",
|
||||
"Strength",
|
||||
"Charisma",
|
||||
"Intuition",
|
||||
"Logic",
|
||||
"Willpower",
|
||||
"Edge",
|
||||
"Essence",
|
||||
"Initiative"
|
||||
};
|
||||
|
||||
static const vector<string> cSkillParameters = {
|
||||
"Name",
|
||||
"RTG.",
|
||||
"ATT.",
|
||||
};
|
||||
|
||||
static const vector<string> cContactsParameters = {
|
||||
"Name",
|
||||
"Loyalty",
|
||||
};
|
||||
|
||||
static const vector<string> cRangedWeaponsParameters = {
|
||||
"Weapon",
|
||||
"Damage",
|
||||
"AP",
|
||||
"Mode",
|
||||
"RC",
|
||||
"Ammo"
|
||||
};
|
||||
|
||||
static const vector<string> cImplantParameters = {
|
||||
"Implant",
|
||||
"Rating",
|
||||
"Essence",
|
||||
"Notes",
|
||||
};
|
||||
|
||||
static const vector<string> cMeleeWeaponParameters = {
|
||||
"Weapon",
|
||||
"Reach",
|
||||
"Damage",
|
||||
"AP",
|
||||
};
|
||||
|
||||
static const vector<string> cArmorParamters = {
|
||||
"Armor",
|
||||
"Ballistic",
|
||||
"Impact",
|
||||
"Notes",
|
||||
};
|
||||
|
||||
ShadowrunCharacterForm::ShadowrunCharacterForm() {
|
||||
html.reserve(30000);
|
||||
|
||||
html += "<form hx-post='/api/shadowrun/submit-character' hx-target='#form-response' hx-swap='innerHTML'>";
|
||||
html += HtmxShAttributeList("Character Info", cCharacterInfo).htmx();
|
||||
html += HtmxShAttributeList("Attributes", cAttributes).htmx();
|
||||
|
||||
html += "<div style='display: grid; grid-template-columns: 1fr 1fr; gap: 2em;'>";
|
||||
html += HtmxShItemList("Active Skills", cSkillParameters, 6).htmx();
|
||||
html += HtmxShItemList("Knowledge Skills", cSkillParameters, 6).htmx();
|
||||
|
||||
// add Qualities
|
||||
html += "<div class='section'>"
|
||||
"<h2>Qualities</h2>"
|
||||
"<label>Positive Qualities:"
|
||||
"<textarea name='positive_qualities' rows='4'></textarea>"
|
||||
"</label>"
|
||||
"<label>Negative Qualities:"
|
||||
"<textarea name='negative_qualities' rows='4'></textarea>"
|
||||
"</label>"
|
||||
"</div>";
|
||||
|
||||
// add datapack notes
|
||||
html += "<div class='section'>"
|
||||
"<h2>Datajack / Commlink / Cyberdeck / Notes</h2>"
|
||||
"<label>Notes:"
|
||||
"<textarea name='datapack_notes' rows='6'></textarea>"
|
||||
"</label>"
|
||||
"</div>";
|
||||
|
||||
html += HtmxShCondition("Physical Condition", 18).htmx();
|
||||
html += HtmxShCondition("Stun Condition", 12).htmx();
|
||||
html += HtmxShItemList("Contacts", cContactsParameters, 6).htmx();
|
||||
html += HtmxShItemList("Ranged Weapons", cRangedWeaponsParameters, 7).htmx();
|
||||
html += HtmxShItemList("Cyberware and Bioware", cImplantParameters, 7).htmx();
|
||||
html += HtmxShItemList("Melee Weapons", cMeleeWeaponParameters, 7).htmx();
|
||||
html += HtmxShItemList("Armor", cArmorParamters , 3).htmx();
|
||||
html += "</div>";
|
||||
|
||||
html += "<div style='text-align:center'>"
|
||||
"<button type='submit'>Submit</button>"
|
||||
"</div>"
|
||||
"</form>";
|
||||
}
|
||||
14
src/shadowrun/ShadowrunCharacterForm.hpp
Normal file
14
src/shadowrun/ShadowrunCharacterForm.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef SHADOWRUN_CHARACTER_FORM_HPP
|
||||
#define SHADOWRUN_CHARACTER_FORM_HPP
|
||||
|
||||
#include "htmx/HtmxObject.h"
|
||||
|
||||
class ShadowrunCharacterForm : public HtmxObject {
|
||||
|
||||
public:
|
||||
ShadowrunCharacterForm();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // SHADOWRUN_CHARACTER_FORM_HPP
|
||||
79
src/utils.cpp
Normal file
79
src/utils.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include "utils.hpp"
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace utils {
|
||||
|
||||
expected<bool, string> isLocalPortOpen(uint16_t portno) {
|
||||
const char *hostname = "localhost";
|
||||
|
||||
int sockfd;
|
||||
bool ret;
|
||||
struct sockaddr_in serv_addr;
|
||||
struct hostent *server;
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0) {
|
||||
close(sockfd);
|
||||
return unexpected("ERROR opening socket");
|
||||
}
|
||||
|
||||
server = gethostbyname(hostname);
|
||||
|
||||
if (server == NULL) {
|
||||
close(sockfd);
|
||||
return unexpected("ERROR, no such host");
|
||||
}
|
||||
|
||||
bzero((char *) &serv_addr, sizeof(serv_addr));
|
||||
serv_addr.sin_family = AF_INET;
|
||||
bcopy((char *)server->h_addr,
|
||||
(char *)&serv_addr.sin_addr.s_addr,
|
||||
server->h_length);
|
||||
|
||||
serv_addr.sin_port = htons(portno);
|
||||
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) {
|
||||
ret = false;
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
string to_id_format(const string& s){
|
||||
string new_s = s;
|
||||
|
||||
// transform(new_s.begin(), new_s.end(), new_s.begin(),
|
||||
// [](unsigned char c){ return std::tolower(c); });
|
||||
|
||||
replace( new_s.begin(), new_s.end(), ' ', '-');
|
||||
|
||||
return new_s;
|
||||
}
|
||||
|
||||
string loadFile(const string& path) {
|
||||
ifstream f(path);
|
||||
stringstream buffer;
|
||||
buffer << f.rdbuf();
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
std::filesystem::path getDataDir(){
|
||||
return std::getenv("XDG_DATA_HOME")
|
||||
? std::filesystem::path(std::getenv("XDG_DATA_HOME")) / APPLICATION_NAME
|
||||
: std::filesystem::path(std::getenv("HOME")) / ".local" / "share" / APPLICATION_NAME;
|
||||
}
|
||||
|
||||
}
|
||||
19
src/utils.hpp
Normal file
19
src/utils.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef UTILS_HPP
|
||||
#define UTILS_HPP
|
||||
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
|
||||
namespace utils {
|
||||
std::expected<bool, std::string> isLocalPortOpen(uint16_t portno);
|
||||
|
||||
std::string to_id_format(const std::string& s);
|
||||
|
||||
std::string loadFile(const std::string& path);
|
||||
|
||||
std::filesystem::path getDataDir();
|
||||
}
|
||||
|
||||
#endif
|
||||
133
templates/shadowrun.html
Normal file
133
templates/shadowrun.html
Normal file
@ -0,0 +1,133 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script src="/static/htmx.min.js"></script>
|
||||
<meta charset="UTF-8">
|
||||
<title>Shadowrun Character Sheet</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
background-color: white;
|
||||
padding: 2em;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
.grid-2 {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.grid-3 {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
.grid-4 {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
|
||||
.grid-6 {
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
}
|
||||
|
||||
.skill-row {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr 1fr;
|
||||
gap: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input[type="text"], input[type="number"] {
|
||||
padding: 0.4em;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 2em;
|
||||
padding: 0.75em 2em;
|
||||
background-color: #222;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
.monitor-track {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, auto);
|
||||
gap: 0.25em;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.monitor-box input[type="checkbox"] {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.monitor-number {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<h1>Shadowrun Character Sheet</h1>
|
||||
|
||||
<div id="character-selector"
|
||||
hx-get="/api/shadowrun/character-list"
|
||||
hx-trigger="load"
|
||||
hx-target="this"
|
||||
hx-swap="outerHTML">
|
||||
</div>
|
||||
<div id="form-container"></div>
|
||||
|
||||
<div id="form-response"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user