vault backup: 2025-04-20 00:15:46
This commit is contained in:
10
.obsidian/workspace.json
vendored
10
.obsidian/workspace.json
vendored
@@ -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",
|
||||
|
||||
@@ -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: Рассчитанные значения
|
||||
// ... другие поля ...
|
||||
};
|
||||
```
|
||||
|
||||
Эта функция — критически важная часть игровой логики, отвечающая за корректное обновление всех динамических параметров объектов в игре.
|
||||
121
PERSONAL PROJECTS/P2EP/pseudoCode/MakeSmallChar.md
Normal file
121
PERSONAL PROJECTS/P2EP/pseudoCode/MakeSmallChar.md
Normal file
@@ -0,0 +1,121 @@
|
||||
``` c
|
||||
#include <libgte.h>
|
||||
#include <libgpu.h>
|
||||
#include <libgs.h>
|
||||
|
||||
/* Структуры данных */
|
||||
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
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user