#include "stdafx.h" #include "config.h" #include "char.h" #include "char_manager.h" #include "regen.h" #include "mob_manager.h" #include "dungeon.h" LPREGEN regen_list = NULL; LPREGEN_EXCEPTION regen_exception_list = NULL; enum ERegenModes { MODE_TYPE = 0, MODE_SX, MODE_SY, MODE_EX, MODE_EY, MODE_Z_SECTION, MODE_DIRECTION, MODE_REGEN_TIME, MODE_REGEN_PERCENT, MODE_MAX_COUNT, MODE_VNUM }; static bool get_word(FILE *fp, char *buf) // ¿öµå´ÜÀ§·Î ¹Þ´Â´Ù. { int i = 0; int c; int semicolon_mode = 0; while ((c = fgetc(fp)) != EOF) { if (i == 0) { if (c == '"') { semicolon_mode = 1; continue; } if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue; } if (semicolon_mode) { if (c == '"') { buf[i] = '\0'; return true; } buf[i++] = c; } else { if ((c == ' ' || c == '\t' || c == '\n' || c == '\r')) { buf[i] = '\0'; return true; } buf[i++] = c; } if (i == 2 && buf[0] == '/' && buf[1] == '/') { buf[i] = '\0'; return true; } } buf[i] = '\0'; return (i != 0); } static void next_line(FILE *fp) { int c; while ((c = fgetc(fp)) != EOF) if (c == '\n') return; } static bool read_line(FILE *fp, LPREGEN regen) { char szTmp[256]; int mode = MODE_TYPE; int tmpTime; DWORD i; while (get_word(fp, szTmp)) { if (!strncmp(szTmp, "//", 2)) { next_line(fp); continue; } switch (mode) { case MODE_TYPE: if (szTmp[0] == 'm') regen->type = REGEN_TYPE_MOB; else if (szTmp[0] == 'g') { regen->type = REGEN_TYPE_GROUP; if (szTmp[1] == 'a') regen->is_aggressive = true; } else if (szTmp[0] == 'e') regen->type = REGEN_TYPE_EXCEPTION; else if (szTmp[0] == 'r') regen->type = REGEN_TYPE_GROUP_GROUP; else if (szTmp[0] == 's') regen->type = REGEN_TYPE_ANYWHERE; else { sys_err("read_line: unknown regen type %c", szTmp[0]); exit(1); } ++mode; break; case MODE_SX: str_to_number(regen->sx, szTmp); ++mode; break; case MODE_SY: str_to_number(regen->sy, szTmp); ++mode; break; case MODE_EX: { int iX = 0; str_to_number(iX, szTmp); regen->sx -= iX; regen->ex = regen->sx + iX * 2; regen->sx *= 100; regen->ex *= 100; ++mode; } break; case MODE_EY: { int iY = 0; str_to_number(iY, szTmp); regen->sy -= iY; regen->ey = regen->sy + iY * 2; regen->sy *= 100; regen->ey *= 100; ++mode; } break; case MODE_Z_SECTION: str_to_number(regen->z_section, szTmp); // ÀͼÁ¼Ç ÀÌ¸é ³ª°¡ÁÖÀÚ. if (regen->type == REGEN_TYPE_EXCEPTION) return true; ++mode; break; case MODE_DIRECTION: str_to_number(regen->direction, szTmp); ++mode; break; case MODE_REGEN_TIME: regen->time = 0; tmpTime = 0; for (i = 0; i < strlen(szTmp); ++i) { switch (szTmp[i]) { case 'h': regen->time += tmpTime * 3600; tmpTime = 0; break; case 'm': regen->time += tmpTime * 60; tmpTime = 0; break; case 's': regen->time += tmpTime; tmpTime = 0; break; default: if (szTmp[i] >= '0' && szTmp[i] <= '9') { tmpTime *= 10; tmpTime += (szTmp[i] - '0'); } } } ++mode; break; case MODE_REGEN_PERCENT: ++mode; break; case MODE_MAX_COUNT: regen->count = 0; str_to_number(regen->max_count, szTmp); ++mode; break; case MODE_VNUM: str_to_number(regen->vnum, szTmp); ++mode; return true; } } return false; } bool is_regen_exception(long x, long y) { LPREGEN_EXCEPTION exc; for (exc = regen_exception_list; exc; exc = exc->next) { if (exc->sx <= x && exc->sy <= y) if (exc->ex >= x && exc->ey >= y) return true; } return false; } static void regen_spawn_dungeon(LPREGEN regen, LPDUNGEON pDungeon, bool bOnce) { DWORD num; DWORD i; num = (regen->max_count - regen->count); if (!num) return; for (i = 0; i < num; ++i) { LPCHARACTER ch = NULL; if (regen->type == REGEN_TYPE_ANYWHERE) { ch = CHARACTER_MANAGER::instance().SpawnMobRandomPosition(regen->vnum, regen->lMapIndex); if (ch) { ++regen->count; ch->SetDungeon(pDungeon); } } else if (regen->sx == regen->ex && regen->sy == regen->ey) { ch = CHARACTER_MANAGER::instance().SpawnMob(regen->vnum, regen->lMapIndex, regen->sx, regen->sy, regen->z_section, false, regen->direction == 0 ? number(0, 7) * 45 : (regen->direction - 1) * 45); if (ch) { ++regen->count; ch->SetDungeon(pDungeon); } } else { if (regen->type == REGEN_TYPE_MOB) { ch = CHARACTER_MANAGER::Instance().SpawnMobRange(regen->vnum, regen->lMapIndex, regen->sx, regen->sy, regen->ex, regen->ey, true); if (ch) { ++regen->count; ch->SetDungeon(pDungeon); } } else if (regen->type == REGEN_TYPE_GROUP) { if (CHARACTER_MANAGER::Instance().SpawnGroup(regen->vnum, regen->lMapIndex, regen->sx, regen->sy, regen->ex, regen->ey, bOnce ? NULL : regen, regen->is_aggressive, pDungeon)) ++regen->count; } else if (regen->type == REGEN_TYPE_GROUP_GROUP) { if (CHARACTER_MANAGER::Instance().SpawnGroupGroup(regen->vnum, regen->lMapIndex, regen->sx, regen->sy, regen->ex, regen->ey, bOnce ? NULL : regen, regen->is_aggressive, pDungeon)) ++regen->count; } } if (ch && !bOnce) ch->SetRegen(regen); } } static void regen_spawn(LPREGEN regen, bool bOnce) { DWORD num; DWORD i; num = (regen->max_count - regen->count); if (!num) return; for (i = 0; i < num; ++i) { LPCHARACTER ch = NULL; if (regen->type == REGEN_TYPE_ANYWHERE) { ch = CHARACTER_MANAGER::instance().SpawnMobRandomPosition(regen->vnum, regen->lMapIndex); if (ch) ++regen->count; } else if (regen->sx == regen->ex && regen->sy == regen->ey) { ch = CHARACTER_MANAGER::instance().SpawnMob(regen->vnum, regen->lMapIndex, regen->sx, regen->sy, regen->z_section, false, regen->direction == 0 ? number(0, 7) * 45 : (regen->direction - 1) * 45); if (ch) ++regen->count; } else { if (regen->type == REGEN_TYPE_MOB) { ch = CHARACTER_MANAGER::Instance().SpawnMobRange(regen->vnum, regen->lMapIndex, regen->sx, regen->sy, regen->ex, regen->ey, true, regen->is_aggressive, regen->is_aggressive ); if (ch) ++regen->count; } else if (regen->type == REGEN_TYPE_GROUP) { if (CHARACTER_MANAGER::Instance().SpawnGroup(regen->vnum, regen->lMapIndex, regen->sx, regen->sy, regen->ex, regen->ey, bOnce ? NULL : regen, regen->is_aggressive)) ++regen->count; } else if (regen->type == REGEN_TYPE_GROUP_GROUP) { if (CHARACTER_MANAGER::Instance().SpawnGroupGroup(regen->vnum, regen->lMapIndex, regen->sx, regen->sy, regen->ex, regen->ey, bOnce ? NULL : regen, regen->is_aggressive)) ++regen->count; } } if (ch && !bOnce) ch->SetRegen(regen); } } EVENTFUNC(dungeon_regen_event) { dungeon_regen_event_info* info = dynamic_cast( event->info ); if ( info == NULL ) { sys_err( "dungeon_regen_event> Null pointer" ); return 0; } LPDUNGEON pDungeon = CDungeonManager::instance().Find(info->dungeon_id); if (pDungeon == NULL) { return 0; } LPREGEN regen = info->regen; if (regen->time == 0) { regen->event = NULL; } regen_spawn_dungeon(regen, pDungeon, false); return PASSES_PER_SEC(regen->time); } bool regen_do(const char* filename, long lMapIndex, int base_x, int base_y, LPDUNGEON pDungeon, bool bOnce) { if (g_bNoRegen) return true; if ( lMapIndex >= 114 && lMapIndex <= 117 ) return true; LPREGEN regen = NULL; FILE* fp = fopen(filename, "rt"); if (NULL == fp) { sys_err("SYSTEM: regen_do: %s: file not found", filename); return false; } while (true) { REGEN tmp; memset(&tmp, 0, sizeof(tmp)); if (!read_line(fp, &tmp)) break; if (tmp.type == REGEN_TYPE_MOB || tmp.type == REGEN_TYPE_GROUP || tmp.type == REGEN_TYPE_GROUP_GROUP || tmp.type == REGEN_TYPE_ANYWHERE) { if (!bOnce) { regen = M2_NEW REGEN; memcpy(regen, &tmp, sizeof(REGEN)); } else regen = &tmp; if (pDungeon) regen->is_aggressive = true; regen->lMapIndex = lMapIndex; regen->count = 0; regen->sx += base_x; regen->ex += base_x; regen->sy += base_y; regen->ey += base_y; if (regen->sx > regen->ex) { regen->sx ^= regen->ex; regen->ex ^= regen->sx; regen->sx ^= regen->ex; } if (regen->sy > regen->ey) { regen->sy ^= regen->ey; regen->ey ^= regen->sy; regen->sy ^= regen->ey; } if (regen->type == REGEN_TYPE_MOB) { const CMob * p = CMobManager::instance().Get(regen->vnum); if (!p) { sys_err("No mob data by vnum %u", regen->vnum); if (!bOnce) { M2_DELETE(regen); } continue; } } if (!bOnce && pDungeon != NULL) { dungeon_regen_event_info* info = AllocEventInfo(); info->regen = regen; info->dungeon_id = pDungeon->GetId(); regen->event = event_create(dungeon_regen_event, info, PASSES_PER_SEC(number(0, 16)) + PASSES_PER_SEC(regen->time)); pDungeon->AddRegen(regen); // regen_id should be determined at this point, // before the call to CHARACTER::SetRegen() } // óÀ½¿£ ¹«Á¶°Ç ¸®Á¨ ÇØÁØ´Ù. regen_spawn_dungeon(regen, pDungeon, bOnce); } } fclose(fp); return true; } bool regen_load_in_file(const char* filename, long lMapIndex, int base_x, int base_y) { if (g_bNoRegen) return true; LPREGEN regen = NULL; FILE * fp = fopen(filename, "rt"); if (NULL == fp) { sys_err("SYSTEM: regen_do: %s: file not found", filename); return false; } while (true) { REGEN tmp; memset(&tmp, 0, sizeof(tmp)); if (!read_line(fp, &tmp)) break; if (tmp.type == REGEN_TYPE_MOB || tmp.type == REGEN_TYPE_GROUP || tmp.type == REGEN_TYPE_GROUP_GROUP || tmp.type == REGEN_TYPE_ANYWHERE) { regen = &tmp; regen->is_aggressive = true; regen->lMapIndex = lMapIndex; regen->count = 0; regen->sx += base_x; regen->ex += base_x; regen->sy += base_y; regen->ey += base_y; if (regen->sx > regen->ex) { regen->sx ^= regen->ex; regen->ex ^= regen->sx; regen->sx ^= regen->ex; } if (regen->sy > regen->ey) { regen->sy ^= regen->ey; regen->ey ^= regen->sy; regen->sy ^= regen->ey; } if (regen->type == REGEN_TYPE_MOB) { const CMob * p = CMobManager::instance().Get(regen->vnum); if (!p) { sys_err("No mob data by vnum %u", regen->vnum); continue; } } // óÀ½¿£ ¹«Á¶°Ç ¸®Á¨ ÇØÁØ´Ù. regen_spawn(regen, true); } } fclose(fp); return true; } EVENTFUNC(regen_event) { regen_event_info* info = dynamic_cast( event->info ); if ( info == NULL ) { sys_err( "regen_event> Null pointer" ); return 0; } LPREGEN regen = info->regen; if (regen->time == 0) regen->event = NULL; regen_spawn(regen, false); return PASSES_PER_SEC(regen->time); } bool regen_load(const char* filename, long lMapIndex, int base_x, int base_y) { if (g_bNoRegen) return true; LPREGEN regen = NULL; FILE* fp = fopen(filename, "rt"); if (NULL == fp) { sys_log(0, "SYSTEM: regen_load: %s: file not found", filename); return false; } while (true) { REGEN tmp; memset(&tmp, 0, sizeof(tmp)); if (!read_line(fp, &tmp)) break; if (tmp.type == REGEN_TYPE_MOB || tmp.type == REGEN_TYPE_GROUP || tmp.type == REGEN_TYPE_GROUP_GROUP || tmp.type == REGEN_TYPE_ANYWHERE) { if (test_server) { CMobManager::instance().IncRegenCount(tmp.type, tmp.vnum, tmp.max_count, tmp.time); } regen = M2_NEW REGEN; memcpy(regen, &tmp, sizeof(REGEN)); INSERT_TO_TW_LIST(regen, regen_list, prev, next); regen->lMapIndex = lMapIndex; regen->count = 0; regen->sx += base_x; regen->ex += base_x; regen->sy += base_y; regen->ey += base_y; if (regen->sx > regen->ex) { regen->sx ^= regen->ex; regen->ex ^= regen->sx; regen->sx ^= regen->ex; } if (regen->sy > regen->ey) { regen->sy ^= regen->ey; regen->ey ^= regen->sy; regen->sy ^= regen->ey; } if (regen->type == REGEN_TYPE_MOB) { const CMob * p = CMobManager::instance().Get(regen->vnum); if (!p) { sys_err("No mob data by vnum %u", regen->vnum); } else if (p->m_table.bType == CHAR_TYPE_NPC || p->m_table.bType == CHAR_TYPE_WARP || p->m_table.bType == CHAR_TYPE_GOTO) { SECTREE_MANAGER::instance().InsertNPCPosition(lMapIndex, p->m_table.bType, p->m_table.szLocaleName, (regen->sx+regen->ex) / 2 - base_x, (regen->sy+regen->ey) / 2 - base_y); } } //NO_REGEN // Desc: regen.txt (¿Ü ¸®Á¨°ü·Ã ÅؽºÆ® ) ¿¡¼­ ¸®Á¨ ½Ã°£À» 0À¸·Î ¼¼ÆÃÇҽà // ¸®Á¨À» ÇÏÁö ¾ÈÇÑ´Ù. if (regen->time != 0) { // óÀ½¿£ ¹«Á¶°Ç ¸®Á¨ ÇØÁØ´Ù. regen_spawn(regen, false); regen_event_info* info = AllocEventInfo(); info->regen = regen; regen->event = event_create(regen_event, info, PASSES_PER_SEC(number(0, 16)) + PASSES_PER_SEC(regen->time)); } //END_NO_REGEN } else if (tmp.type == REGEN_TYPE_EXCEPTION) { LPREGEN_EXCEPTION exc; exc = M2_NEW REGEN_EXCEPTION; exc->sx = tmp.sx; exc->sy = tmp.sy; exc->ex = tmp.ex; exc->ey = tmp.ey; exc->z_section = tmp.z_section; INSERT_TO_TW_LIST(exc, regen_exception_list, prev, next); } } fclose(fp); return true; } void regen_free(void) { LPREGEN regen, next_regen; LPREGEN_EXCEPTION exc, next_exc; for (regen = regen_list; regen; regen = next_regen) { next_regen = regen->next; event_cancel(®en->event); M2_DELETE(regen); } regen_list = NULL; for (exc = regen_exception_list; exc; exc = next_exc) { next_exc = exc->next; M2_DELETE(exc); } regen_exception_list = NULL; } void regen_reset(int x, int y) { LPREGEN regen; for (regen = regen_list; regen; regen = regen->next) { if (!regen->event) continue; // ÁÂÇ¥°¡ ÀÖÀ¸¸é ÁÂÇ¥ ³»¿¡ ÀÖ´Â ¸®Á¨ ¸®½ºÆ®¸¸ ¸®Á¨ ½ÃŲ´Ù. if (x != 0 || y != 0) { if (x >= regen->sx && x <= regen->ex) if (y >= regen->sy && y <= regen->ey) event_reset_time(regen->event, 1); } // ¾øÀ¸¸é ÀüºÎ ¸®Á¨ else event_reset_time(regen->event, 1); } }