diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index 8bd2eb5..38ebbb6 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -41,12 +41,12 @@ "state": { "type": "markdown", "state": { - "file": "PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80012df4 RenderInterface.md", + "file": "PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80015674 Update Entity Stats.md", "mode": "source", "source": false }, "icon": "lucide-file", - "title": "FUN_80012df4 RenderInterface" + "title": "FUN_80015674 Update Entity Stats" } } ], @@ -207,8 +207,10 @@ }, "active": "dd912cc876184c4f", "lastOpenFiles": [ - "PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80011f2c InitInterfaceManager.md", + "PERSONAL PROJECTS/P2EP/pseudoCode/MakeSmallChar.md", + "PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80015674 Update Entity Stats.md", "PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80012df4 RenderInterface.md", + "PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80011f2c InitInterfaceManager.md", "PERSONAL PROJECTS/PS1 DOCS/PS1 IRQ.md", "PERSONAL PROJECTS/P2EP/pseudoCode", "PERSONAL PROJECTS/PS1 DOCS/Untitled", @@ -241,9 +243,7 @@ "WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud/Alfa cloud prod.canvas", "WORK & PROJECTS/Mol/Планы и диаграммы/00001_Быстрый старт/Быстрый старт.canvas", "My/Diet 1.md", - "My/Diet 2.md", "My", - "WORK & PROJECTS/Mol/Планы и диаграммы/MOL _ План разработки.md", "WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud", "Структура объектов испытаний.png", "Схема связей юрлиц и адресов.png", diff --git a/PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80015674 Update Entity Stats.md b/PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80015674 Update Entity Stats.md new file mode 100644 index 0000000..ddc0469 --- /dev/null +++ b/PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80015674 Update Entity Stats.md @@ -0,0 +1,135 @@ +Эта функция представляет собой **систему управления игровыми объектами или характеристиками персонажа** в игре на PS1. Вот детальный анализ: + +### 🔍 Основное назначение +Функция выполняет: +1. **Обновление параметров объекта** (персонажа, предмета или системы) +2. **Расчет характеристик** на основе базовых значений и модификаторов +3. **Обработку двух режимов работы** (нормальный и специальный через флаг 0x8000) + +### 📌 Полная реконструкция на C +```c +// Структура объекта игры (реконструкция) +typedef struct { + uint32_t id; // ID объекта + флаги (param_1) + uint16_t type; // Тип объекта + uint16_t subtype; // Подтип + uint8_t base_stats[10]; // Базовые характеристики + uint8_t modifiers[10]; // Модификаторы + uint16_t calculated[8]; // Рассчитанные значения + // ... другие поля ... +} GameEntity; + +// Глобальные данные (реконструкция) +extern uint16_t DWORD_8006eb8c[]; // Таблицы характеристик +extern uint16_t DWORD_800830d0[]; // Базовая статистика + +void UpdateEntityStats(GameEntity* target, GameEntity* source, int offset, bool apply_modifiers) +{ + // Проверка специального флага + if ((source->id & 0x8000) == 0) { + // Нормальный режим ------------------------------------------------- + + // 1. Поиск нужного объекта в массиве + int entity_index = 0; + GameEntity* current = source; + while(entity_index < 7) { + if (current->type == (source->id & 0x7FFF)) break; + entity_index++; + current = (GameEntity*)((char*)current + 0x54); // Следующий объект + } + + // 2. Копирование базовых параметров + if (!apply_modifiers) { + memcpy(target, current, sizeof(GameEntity)); // Частичное копирование + } + + // 3. Расчет комбинированных характеристик + for (int i = 0; i < 5; i++) { + // Среднее значение между базой и модификатором + uint8_t combined = (current->base_stats[i] + + (current->modifiers[i] + source->modifiers[i]) / 2) / 2; + + // Ограничение значений (макс 99) + target->modifiers[i] = (combined > 99) ? 99 : combined; + } + + // 4. Сложные расчеты характеристик + int calculated_value = + (current->base_stats[9] * DWORD_8006eb8c[(current->type-1)*4] + + current->modifiers[9] * DWORD_8006eb8c[(current->type-1)*4+1]) / 1000; + + // 5. Применение ограничений + calculated_value += DWORD_800830d0[entity_index*0x54 + 2]; + target->calculated[0] = (calculated_value > 999) ? 999 : calculated_value; + + // 6. Обновление связанных объектов + if (!apply_modifiers) { + current->calculated[0] = target->calculated[0]; + } + + // ... аналогичные расчеты для других характеристик ... + + } else { + // Специальный режим (по ID) --------------------------------------- + + uint16_t special_id = source->id & 0xFFF; + + // 1. Загрузка данных из специальной таблицы + uint8_t* special_data = (uint8_t*)(0x80062b04 + special_id * 0x20); + + // 2. Инициализация объекта + target->id = 9; // Специальный тип + target->type = source->id | 0x8000; // Сохраняем флаг + + // 3. Копирование характеристик + memcpy(target->modifiers, special_data + 1, 5); + + // 4. Расчет производных значений + target->calculated[0] = *(uint16_t*)(0x80062b00 + special_id * 0x20 + 2); + target->calculated[4] = special_data[0] + special_data[1] * 3; + + // ... дополнительные расчеты ... + } +} +``` + +### 🔧 Технические особенности +1. **Два режима работы**: + - Нормальный (поиск по типу объекта) + - Специальный (прямой доступ по ID с флагом 0x8000) + +2. **Система характеристик**: + - Базовые значения + - Модификаторы + - Рассчитанные итоговые значения с ограничениями (например, макс. 999) + +3. **Оптимизации PS1**: + - Фиксированные смещения (0x54, 0x20) + - Работа с префиксом 0x80000000 (адресация KSEG0) + +### 🌟 Что делает на практике? +1. **Для персонажей**: + - Пересчитывает HP/MP/статы на основе уровня и экипировки + - Применяет временные модификаторы (баффы/дебаффы) + +2. **Для предметов**: + - Обновляет параметры при экипировке + - Рассчитывает комбинированные эффекты + +3. **Для системных объектов**: + - Управляет специальными объектами через ID + +### 📊 Структура данных +```c +// Пример структуры объекта (0x54 байта) +struct { + uint32_t id_flags; // 0x00: ID + флаги + uint16_t type; // 0x04: Тип объекта + uint16_t subtype; // 0x06: Подтип + uint8_t stats[10]; // 0x08: Основные характеристики + uint16_t calculated[8]; // 0x12: Рассчитанные значения + // ... другие поля ... +}; +``` + +Эта функция — критически важная часть игровой логики, отвечающая за корректное обновление всех динамических параметров объектов в игре. \ No newline at end of file diff --git a/PERSONAL PROJECTS/P2EP/pseudoCode/MakeSmallChar.md b/PERSONAL PROJECTS/P2EP/pseudoCode/MakeSmallChar.md new file mode 100644 index 0000000..986bcab --- /dev/null +++ b/PERSONAL PROJECTS/P2EP/pseudoCode/MakeSmallChar.md @@ -0,0 +1,121 @@ +``` c +#include +#include +#include + +/* Структуры данных */ +typedef struct { + uint* next_block; // Следующий блок DMA (младшие 24 бита) + uint control; // Контрольные биты DMA + uint data_addr; // Адрес данных + uint tpage_params; // Параметры текстуры (TPage) +} DMAControlBlock; + +typedef struct { + short x, y; // Позиция символа + short char_width; // Ширина символа + ushort flags; // Флаги рендеринга + uint* dma_head; // Голова DMA-цепочки + uint* dma_tail; // Хвост DMA-цепочки +} TextRenderState; + +/* Константы */ +#define SCRAM_BASE 0x1F800000 // Быстрая память PS1 +#define DMA_MAGIC 0x80000000 // Флаг DMA-блока +#define CHAR_OFFSET 0x20 // Смещение ASCII-кодов + +/* Глобальные переменные (аналоги оригинальных) */ +static uint* gDmaNextFree = (uint*)0x8007CE68; +static uint* gDmaCounter = (uint*)0x8007CE6C; +static uint gActiveTpage = 0x8007CA0C; + +/* Основная функция рендеринга текста */ +DMAControlBlock* RenderTextSystem( + const char* text, + short base_x, + short base_y, + uint color_flags, + uint tpage_config +) { + /* Инициализация состояния */ + TextRenderState state; + state.x = base_x; + state.y = base_y; + state.flags = color_flags; + + /* Получаем начальный DMA-блок из SCRAM */ + DMAControlBlock* dma_blocks = (DMAControlBlock*)(*gDmaNextFree | DMA_MAGIC); + state.dma_head = state.dma_tail = (uint*)dma_blocks; + + /* Настройка параметров рендеринга */ + StoreColorToAddr(color_flags, tpage_config); + InitDMAtextChain(dma_blocks, base_x, base_y); + + /* Основной цикл обработки текста */ + while (*text) { + char current_char = *text++; + ushort char_code = current_char - CHAR_OFFSET; + + /* Особые обработки для специфичных символов */ + switch (current_char) { + case 'g': case 'j': case 'p': case 'q': case 'y': + base_y += 2; // Смещение для символов с хвостами + break; + } + + /* Позиционирование символа */ + short render_x, render_y; + if (state.flags & 0x10) { + /* Альтернативный режим позиционирования */ + render_x = base_x - GetCharLeftOffset(char_code); + render_y = base_y + GetCharBaseline(char_code); + } else { + /* Стандартный режим */ + render_x = base_x + dma_blocks->char_width * 8; + render_y = base_y; + } + + /* Генерация DMA-команд для символа */ + DMAControlBlock* new_block = AllocDMABlock(); + SetupCharRender(new_block, char_code, render_x, render_y); + + /* Добавление в цепочку */ + state.dma_tail->next_block = (uint)new_block & 0xFFFFFF; + state.dma_tail = new_block; + + /* Обновление позиции */ + if (dma_blocks->char_width == 0) { + state.dma_head = new_block; + dma_blocks->char_width = 1; + } + } + + /* Финализация текстурных страниц */ + for (int i = 0; i < 2; i++) { + DMAControlBlock* tpage_block = AllocDMABlock(); + SetDrawTPage(tpage_block, 0, 1, gActiveTpage); + state.dma_tail->next_block = (uint)tpage_block & 0xFFFFFF; + state.dma_tail = tpage_block; + } + + return dma_blocks; +} + +/* Вспомогательные функции */ +static DMAControlBlock* AllocDMABlock() { + DMAControlBlock* block = (DMAControlBlock*)(*gDmaNextFree | DMA_MAGIC); + (*gDmaCounter)--; + *gDmaNextFree = (*gDmaNextFree & 0xFF000000) | (*block & 0xFFFFFF); + return block; +} + +static void SetupCharRender(DMAControlBlock* block, ushort char_code, short x, short y) { + /* Настройка параметров символа */ + block->control = 0x1000000; // Базовые флаги DMA + block->data_addr = GetCharDataAddr(char_code); + block->tpage_params = (y << 16) | x; // Позиция + + /* Дополнительные настройки из оригинального кода */ + block->control |= 0x64808080; // Специфичные флаги PS1 +} +``` \ No newline at end of file